Enphase zonnepanelen toevoegen

Je moet niet schakelen tussen verschillende apps als je in de Homey app een nieuw apparaat toevoegt, dat leidt onherroepelijk tot die foutmelding.

Oke alles gewist van de App en opnieuw geinstalleerd, krijg nu de melding: Error: [object Object] bij het aanmelden

Ik zie op Github van de App dat meer mensen dit hebben, dit is gebruik van de locale API.
Maar is dit een Homey ding of een Enphase ding?

Krijg het namelijk ook als ik een webhook stuur met:
http://192.168.2.123/api/v1/production/

(Ben nu niet thuis, anders eens via een browser proberen vanavond)

Ja, en nee :stuck_out_tongue:

Homey zou een optie moeten hebben om self-signed certificates te kunnen ignoren, en Enphase zou iets anders moeten verzinnen in plaats van self-signed certificates.

import json 
import requests
import time
 
user = 'user@user.com'
password = 'password'
envoy_serial = '123456789012'
myenvoy = 'https://192.168.1.1'
 
def getToken():
    data = {'user[email]': user, 'user[password]': password}
    response = requests.post('https://enlighten.enphaseenergy.com/login/login.json', data=data)
    response_data = json.loads(response.text)
    data = {'session_id': response_data['session_id'], 'serial_num': envoy_serial, 'username': user}
    response = requests.post('https://entrez.enphaseenergy.com/tokens', json=data)
    global token_raw
    token_raw = response.text
    return True
 
def checkAuth( sess, header ):
    response = sess.get( myenvoy + "/auth/check_jwt", headers=header, verify=False  )
    if response.status_code == 401:
        return False
    return True
 
getToken()
 
if token_raw=='':
    print("Failed to get token\n")
    quit()
    
authorization_header = { "Authorization": "Bearer " + token_raw }
session = requests.Session()
 
if not checkAuth( session, authorization_header ):
		print( "Failed to authorize\n" )
		quit()
 
e_home = session.get( myenvoy + "/api/v1/production", data=authorization_header, verify=False )
print( e_home )
 
if e_home.status_code == 401:
    print( "Failed to read 'home.json'\n" )
    quit()
 
print( e_home.text )

Dit python scripje werkt wel op de PC maar krijg alleen als data alles null terug:

{
  "wattHoursToday": 0,
  "wattHoursSevenDays": 0,
  "wattHoursLifetime": 0,
  "wattsNow": 0
}

Sinds firmware v7 van de Envoy is er een nieuwe versie van de API en daarbij is de authenticatie gewijzigd. Ik verwacht dat de v1 van de API het überhaupt niet meer gaat doen.
Voor meer info, zie hier:
https://store-d9.enphase.com/download/iq-gateway-access-using-token-tech-brief?_ga=2.178517858.713536855.1675064458-354601911.1671617351

Met een beetje zoeken en spieken van andere heb ik nu een werkend pyton sciptje gemaakt.
Krijg je alle data van de inverters en van de productie.
Je hebt een token nodig en die kan die van internet halen, dat doe ik nu dus maar alleen als het nodig is. De rest gebeurt allemaal op de locale Wifi. @Diederik kan je hier wat mee? Is alleen voor FW7

import requests
import datetime
import json
import time
from requests.auth import HTTPBasicAuth, HTTPDigestAuth

gInlog = 'info@mail.nl'
gPassword = '123456'
gIP = '192.168.2.123' 
authToken = ""  

while True:

   print('Get serialnumber and version firmware and test LAN connection to Envoy')
   try:
       systemXML = requests.get('http://' + gIP + '/info.xml', verify=False)
       if "<sn>" in systemXML.text:
           envoyserial= systemXML.text.split("<sn>")[1].split("</sn>")[0]
       else:
           print('Serial not found')
       if "<software>" in systemXML.text:
           envoyfirmware= systemXML.text.split("<software>")[1].split("</software>")[0][:2] #note [:2] first 2 chars
       else:
           print('Firmware not found')   
   except Exception as err:
       print('Error connection...')
       break


   if authToken == "":
       print('Go login with Enphase Enlighten Account')
       data = {
        'user[email]': gInlog,
        'user[password]': gPassword
       }
       try:
           response = requests.post('https://enlighten.enphaseenergy.com/login/login.json?', data=data)
       except Exception as err:
           print('Error login...')
           break

       response_data = json.loads(response.text)
       print("Got sessionId '" + response_data['session_id'] + "' from Enphase Enlighten.")

       print('Get authToken')
       data = {
        'session_id': response_data['session_id'],
        'serial_num': envoyserial,
        'username': gInlog
       }

       try:
           response = requests.post('https://entrez.enphaseenergy.com/tokens', json=data)
       except Exception as err:
           print('Error token...')
           break

       authToken = response.text
       print("Got authToken '" + authToken + "' from Enphase Energy.")

   if authToken != "":

       print('Validate token on IQ Gateway')
       headers = {
               "Authorization": "Bearer " + authToken
       }
       try:
           response = requests.get('https://' + gIP + '/auth/check_jwt', headers=headers, verify=False)
       except Exception as err:
           print('Error auth...')
           break

       print('Check response, a valid response will look like: <!DOCTYPE html><h2>Valid token.</h2>')
       if "Valid token." in response.text:

           print('Extract the sessionId from the cookies.')
           sessionId = response.cookies['sessionId']

           if sessionId != '':
               print("Got sessionId '" + sessionId + "' from {}".format(gIP) )
           else:
               print("Error getting sessionId and/or authToken using Enphase Enlighten username and password.")
               break

           try:
               jsoninverters = requests.get('http://' + gIP + '/api/v1/production/inverters/' ,cookies=dict(sessionid=sessionId), verify=False)
           except Exception as err:
               print("Error connecting to Enphase Envoy on {} error: {}".format(gIP , err) )
               
        
           if (jsoninverters.status_code == 200):
               inverters=jsoninverters.json()
               for inverter in inverters:
                   print( 'Inverter: ' + inverter['serialNumber'] + ' Lastreport: ' + str(inverter['lastReportDate'])  + ' Reports: ' + str(inverter['lastReportWatts']) )

           try:
               jsonproduction = requests.get('https://' + gIP + '/production.json', cookies=dict(sessionid=sessionId), verify=False)
           except Exception as err:
               print("Error connecting to Enphase Envoy on {} error: {}".format(gIP, err) )
               break 
                           
           if (jsonproduction.status_code == 200):
               production=jsonproduction.json()['production'][0]
               print('Total production read {} Watts, counter is {}'.format(production['wNow'], production['whLifetime']))
               
       else:
           authToken = ""
   else:
       authToken = ""

   print('Wait....')
   time.sleep(10)

print('Exited...')
1 Like

Bedankt, ik heb het omgezet naar C# code en het werkt voor mij.

        static string email = "info@mail.com";
        static string password = "password";
        static string baseUri = "https://192.168.0.59/";
        static string token = "";
        static string envoyserial = "";

        static void EnphaseThread()
        {

            var cookieContainer = new CookieContainer();
            var handler = new HttpClientHandler();
            handler.ClientCertificateOptions = ClientCertificateOption.Manual;
            handler.CookieContainer = cookieContainer;
            handler.ServerCertificateCustomValidationCallback =
                (httpRequestMessage, cert, cetChain, policyErrors) =>
                {
                    return true;
                };

            var client = new HttpClient(handler);

            client.BaseAddress = new Uri(baseUri);

            using (var r = client.GetAsync("info.xml").Result)
            {
                var c = r.Content.ReadAsStringAsync().Result;
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(c);
                envoyserial = doc.SelectSingleNode("//device/sn/text()").Value;
            }
            if (File.Exists("token.txt"))
                token = File.ReadAllText("token.txt");

            if (string.IsNullOrEmpty(token))
            {
                RefreshToken(client);
            }
            else
            {
                Console.WriteLine(DateTime.Now + " Start with existing Enphase token");
            }
            var production = -1;
            var lifetime = -1;

            while (true)
            {
                Thread.Sleep(5000);
                try
                {
                    var requestData = new HttpRequestMessage
                    {
                        Method = HttpMethod.Get,
                        RequestUri = new Uri(client.BaseAddress, "auth/check_jwt"),
                    };
                    requestData.Headers.TryAddWithoutValidation("Authorization", String.Format("Bearer {0}", token));
                    using (var r4 = client.SendAsync(requestData).Result)
                    {
                        if (!r4.IsSuccessStatusCode)
                        {
                            Console.WriteLine(DateTime.Now + " production.json http response: " + r4.StatusCode);
                            continue;
                        }
                        var c2 = r4.Content.ReadAsStringAsync().Result;
                        if (!c2.Contains("Valid token."))
                        {
                            RefreshToken(client);
                            continue;
                        }
                    }
                    using (var r2 = client.GetAsync("production.json").Result)
                    {
                        if (!r2.IsSuccessStatusCode)
                        {
                            Console.WriteLine(DateTime.Now + " auth/check_jwt http response: " + r2.StatusCode);
                            continue;
                        }
                        var d = r2.Content.ReadAsStringAsync().Result;
                        try
                        {
                            var j2 = JsonDocument.Parse(d);
                            var newProduction = 0;
                            var newLifeTime = 0;
                            foreach (var j3 in j2.RootElement.GetProperty("production").EnumerateArray())
                            {
                                newProduction += j3.GetProperty("wNow").GetInt32();
                                newLifeTime += j3.GetProperty("whLifetime").GetInt32();
                            }
                            if (newProduction != production)
                            {
                                production = newProduction;
                                //TODO save value here
                            }
                            if (newLifeTime != lifetime)
                            {
                                lifetime = newLifeTime;
                                //TODO save value here
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(DateTime.Now + " Error in production data: " + d);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(DateTime.Now + " Error: " + ex.Message);
                }
            }
        }

        public static void RefreshToken(HttpClient client)
        {
            Console.WriteLine(DateTime.Now + " Refreshing token");
            var content = new FormUrlEncodedContent(new[]
            {
                new KeyValuePair<string, string>("user[email]", email),
                new KeyValuePair<string, string>("user[password]", password),
            });
            using (var r3 = client.PostAsync("https://enlighten.enphaseenergy.com/login/login.json?", content).Result)
            {
                try
                {
                    if (!r3.IsSuccessStatusCode)
                    {
                        Console.WriteLine(DateTime.Now + " login http error: " + r3.StatusCode);
                        return;
                    }
                    var c3 = r3.Content.ReadAsStringAsync().Result;
                    var j = JsonDocument.Parse(c3);

                    var session_id = j.RootElement.GetProperty("session_id").GetString();

                    var t = new JsonObject
                    {
                        ["session_id"] = session_id,
                        ["serial_num"] = envoyserial,
                        ["username"] = email
                    };

                    using (var r2 = client.PostAsync("https://entrez.enphaseenergy.com/tokens", new StringContent(t.ToString(), Encoding.UTF8, "application/json")).Result)
                    {
                        if (!r2.IsSuccessStatusCode)
                        {
                            Console.WriteLine(DateTime.Now + " tokens http error: " + r2.StatusCode);
                            return;
                        }
                        token = r2.Content.ReadAsStringAsync().Result;
                        File.WriteAllText("token.txt", token);
                        Console.WriteLine(DateTime.Now + " got new token");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(DateTime.Now + " error getting token: " + ex.Message);
                }
            }
        }

Heb het nu ook in een app versie draaien op Homey, even kijken of het stabiel blijft draaien.
Dan deel ik het wel.

2 Likes

Goede avond!
Ook ik probeer al een tijdje m’n enphase panelen te koppelen. Komt er een nieuwe app voor? In de normale store of hcs?
In ieder geval dank voor alles wat jullie als developers allemaal doen :ok_hand::ok_hand:

2 Likes

De versie van mij lijkt te werken, geen problemen gehad.
Weet niet hoe die draait op de HP2023, maar dan kan ik hem wel naar de store zetten.

5 Likes

@Slof Kun je hem alvast voor de oude Homey’s naar de store zetten? Hoor het graag als het lukt!
Heeel erg bedankt!

2 Likes

Als het werkt zou ik m ook graag gebruiken met de huidige app van zonnepanelen krijg ik enphase niet aan de praat

2 Likes

Al de test app geprobeerd? Ik heb zelf SolarEdge maar de laatst officiële app was/werd erg instabiel en moest ik steeds herstarten. Sinds ik de test app draai geen last meer van gehad.

1 Like

I have 5.1.2 running, but Enphase isnt working, so i assume i have to wait a little bit longer, right?

Zojuist de testversie op mijn HP23 geïnstalleerd.
Eerst Enphase Enlighten geprobeerd toe te voegen. Dan om het ID en en api in te vullen, deze waren niet goed volgens de app. Api kopieren ging niet vanuit de Enphase app dus een screenshot door mijn tablet laten omzetten naar tekst, daar kan ook een fout in hebben gezeten.
Daarna Enphase Envoy toegevoegd en meteen werd de huidige vermogen (produktive) , huidig Vermögen (verbruik) , totale opbrengst vandaag en totaal verbruik vandaag weergegeven.

1 Like

Hoi Mike, heb jij Enlighten nu werkend gekregen? Heb jij een api key voor v4, of een oudere versie? ik kan nl alleen een key krijgen voor v4, niet de oudere.

@Stefan_Veenhof Ik heb geprobeerd mijn Enphase toe te voegen met de api maar dat lukte niet.
Toen de Enphase Envoy toegevoegd en dan word het systeem meteen gezien.
Verder niet hoeven invullen of iets dergelijks.