Skip to content

Regulation not smooth as F1ATB #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Chilgl0rd opened this issue Jan 21, 2025 · 21 comments
Open

Regulation not smooth as F1ATB #54

Chilgl0rd opened this issue Jan 21, 2025 · 21 comments
Labels
enhancement New feature or request question Further information is requested

Comments

@Chilgl0rd
Copy link

Hello Xavier,

I started Solar Router with F1ATB and then I found yours. I like your integration with ESPHome/HA ! It is much more integrated with HA and give more flexibility and easiest way to customize.
I tested today both with the same configuration and clear blue sky (1600-1900w production) :-)
Same radiator regulated with SSR, reactivity to 50 on both, stable electricity consumption (#500w), target -10w
I have also Enphase with 1100W batteries. Grid probe via Enphase and Qubino Smart Meter Z-Wave Sensor.
I tested both 10 min each and waiting batteries are 100% charging
But it look like in that configuration F1ATB is more stable and smooth.
As you can see in the snapshot, 13:13 to 13h23 F1ATB and then your implementation.
It is a shame to not have the same behavior.

And idea why ? More conflict with the batteries ?
Maybe in a future add a priority option to battery

Image

Best regards,
Xtof

@XavierBerger
Copy link
Owner

Like we say in French : "Tu compares des choux et des carottes"...

Why did you expect setting the reactivity to 50 on both router will produce the same result?
Reactivity is not something scientifically defined and algorithm of F1ATB and mine are different.

The idea behind this keyword is to allow the user to fine tune the reactivity of the energy diverted to avoid flickering.
Maybe a reactivity of 50 on F1ATB is equivalent to a reactivity of 25.2548 on my router... I don't know.
So If you expect to have the same output, you will have to fine tune your configuration and check how the output curve is impacted.

The best way to regulate a signal is to implement a PID (Proportional Integral Derivate) regulation.
This is what is done in this router for example : YaSolR.
Reactivity is simpler to implement and is good enough for a solar router.

@Chilgl0rd
Copy link
Author

Well, why not ;-) As F1ATB was an inspiration I believed this part was very similar. I tried other values without smoother behavior.
In that state, more energy is lost and more energy come from the grid :-/
Yes PID is a standard to regulate and not have such spikes in/out grid. It is typical for thermal regulation.

Auto-calibration can be a good feature to help finding the best reactivity, if it exists.
Trottle beween multiple Solar Routers should be nice too in order to dispatch the load.

It is a shame 😭

Bien à toi,
Xtof

@XavierBerger
Copy link
Owner

Ok, let's try to understand what happens.

It look like you have an enphase system. It is not natively supported.

So how do you do to get the grid exchange values?
Can you share here your configuration?

As far as I remember enphase is providing a measure every 400ms. This could be an explanation. If you can test it, we can create a power meter dedicated to enphase and compare.

@XavierBerger
Copy link
Owner

About multiple router management, this is also an idea I have to work on since starting from today, I have two which may run at the same time ... Maybe you can open an issue about this and describe your needs. It could help me during the development of this feature.

@Chilgl0rd
Copy link
Author

Chilgl0rd commented Jan 21, 2025

Thanks Xavier 🙏
It that case, I get the grid exchange value via your HA Power Meter package retrieving a Zwave Sensor: https://devices.zwave-js.io/?jumpTo=0x0159:0x0007:0x0052:0.0

F1ATB is using a native integration to Enphase API

The YAML of the ESP32 is the following

esphome:
  name: lctsr02
  friendly_name: LCTSR02

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:
  baud_rate: 115200
  level: INFO
  logs:
    component: ERROR
    light: ERROR

# Enable Home Assistant API
api:
  encryption:
    key: !secret solar_router_02_api_encryption_key

ota:
  - platform: esphome
    password: !secret solar_router_02_ota_password

# Enable improv serial
improv_serial:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

# Activate web interface
web_server:
  port: 80

binary_sensor:
  - platform: gpio
    name: "Switch"
    pin:
      number: GPIO13
      inverted: True
      mode:
        input: true
        pullup: true
    filters:
      - delayed_on: 10ms
    

substitutions:
  # Power meter source -----------------------------------------------------------
  # Sensor in home assistant gathering the power consumption
  main_power_sensor: sensor.power_supply_electric_consumption_w

  # Regulator configuration ------------------------------------------------------
  # Define GPIO pin connected to the relay gate.
  regulator_gate_pin: GPIO33

  # LEDs -------------------------------------------------------------------------
  # Green LED is reflecting regulation status
  # Yellow LED is reflecting power meter status
  green_led_pin: GPIO25
  yellow_led_pin: GPIO26
  red_led_pin: GPIO27

  # power_meter_activated has to be set to 1 to activate the power measurment read
  power_meter_activated_at_start: "1"

  # Temperature sensor
  #temperature_sensor: sensor.lctsr02_temperature
    
  # Sensor in home assistant gathering the temperature
  DS18B20_pin: GPIO32
  # Safety limit LED configuration
  red_led_inverted: "False"
  temperature_update_interval: 60s


packages:
  common:
    url: https://github.com/XavierBerger/Solar-Router-for-ESPHome/
    file: solar_router/common.yaml
    refresh: 1d
  power_meter:
    url: https://github.com/XavierBerger/Solar-Router-for-ESPHome/
    file: solar_router/power_meter_home_assistant.yaml
    refresh: 1d
  regulator:
    url: https://github.com/XavierBerger/Solar-Router-for-ESPHome/
    file: solar_router/regulator_solid_state_relay.yaml
    refresh: 1d
  solar_router:
    url: https://github.com/XavierBerger/Solar-Router-for-ESPHome/
    file: solar_router/engine.yaml
    refresh: 1d
  energy_counter:
    url: https://github.com/XavierBerger/Solar-Router-for-ESPHome/
    file: solar_router/energy_counter_theorical.yaml
    refresh: 1d
  temperature_limiter:
    url: https://github.com/XavierBerger/Solar-Router-for-ESPHome/
    file: solar_router/temperature_limiter_DS18B20.yaml
    refresh: 1d

The HA is

Image

It seems the ZWave Sensor is more difined than Enphase in HA:

Image

@XavierBerger
Copy link
Owner

OK, here is what happen (presumably).

ZWave read the information and HA read this information (I don't know how often, let's say 600ms) - Solar-Router read information from ESPHome (every second).
So between the measurement and the control apply by solar router, 1600ms has passed. So it means that the reaction will come 1,6 second too late.

As far as I remember, Enphase is providing an updated value every 400ms. It is then possible to have 4 time more samples to react.

Conclusion: requesting directly EnPhase will be far better because, we will have more point for the regulation. We will remove some network communication (taking some time). We will also remove the dependency to HA which is a point of failure on the current architecture.

I'll take a look on the internet to see how I can query a EnPhase product and propose a dedicated engine and I'll will ask you to validate it. (Note: I can't tell you when because developing this router is not my main occupation...).

@Chilgl0rd
Copy link
Author

Good point !! I think your analysis is good, if reaction is late it is less stable and be chaos. It needs to be at least twice faster than the physical behavior if I remember Fourier :-)
Maybe you can have a look to F1ATB Code. It was implemented natively. The API needs local IP, login/pwd and serial number of the gateway. It is a popular solar provider.
I will be happy to test the implementation for you and the community.
Don't worry, I know what it is to offer time on such initiative.
I saw the features you work on, you rock !

@XavierBerger
Copy link
Owner

Hello,

Voici un code python que j'ai fait générer par une IA pour récupérer les données d'un Envoy-S (j'espère qu'il fonctionne).

import requests
import json

# Configuration
ENVOY_IP = "192.168.1.XX"  # Remplacez par l'adresse IP de votre Envoy-S
TOKEN = "votre_token_ici"  # Remplacez par votre token d'authentification

# URL de l'API
url = f"https://{ENVOY_IP}/ivp/meters/reports"

# En-têtes de la requête
headers = {
    "Accept": "application/json",
    "Authorization": f"Bearer {TOKEN}"
}

try:
    # Effectuer la requête GET
    response = requests.get(url, headers=headers, verify=False)
    response.raise_for_status()

    # Analyser la réponse JSON
    data = response.json()
    print(json.dumps(data, indent=2))

    # Extraire la production et la consommation
    production = data.get("production", [{}])[0].get("currW", 0)
    print(f"Production actuelle : {production} W")

    consumption = data.get("consumption", [{}])[0].get("currW", 0)
    print(f"Consommation actuelle : {consumption} W")

except requests.exceptions.RequestException as e:
    print(f"Erreur lors de la requête : {e}")
except json.JSONDecodeError:
    print("Erreur lors du décodage de la réponse JSON")

Peux-tu me dire si avec ça tu arrives à récupérer les données de consommation et production ?
Si oui, peux-tu me fournir le json affiché ?

Important : Dans les issues, encadre le code que tu ajoutes par 3 backquote (altg+7), ça fera un formatage correct (ou alors, tu cliques sur l'icône <> dans la barre de boutons). J'ai édité ton commentaire avec la conf yaml, tu peux regarder comment faire si je ne suis pas assez clair.

Note : il faut un token à récupérer sur l'interface de EnPhase qui va bien. Est-ce que tu pourrais écrire une doc qui explique comment faire (en anglais et avec copie d'écran) pour qu'on puisse l'intégrer de la doc du routeur ? Dans mon idée le token sera récupéré une fois par l'utilisateur et rajouté dans ses secrets.

@Chilgl0rd
Copy link
Author

Chilgl0rd commented Jan 22, 2025

Ilooo,

Je ne suis pas encore passé par ton code. Je vais vérifier d'abord la pérénité du token car j'ai lu que c'était valide 12h. ensuite je peux faire la doc qui va bien si nécessaire.
Toutes les integrations que je vois prennent en entrée à minima:

  • local_ip
  • login
  • pwd
  • serial_number
    et pas le token. Probablement pour cette raison.

J'ai trouvé aussi une très bonne documentation sur tout ça avec le code en python: https://mesgeekeries.ch/2023/11/04/decouvrir-les-api-enphase-iq-gateway-envoy-s/

A toute fin utile, le JSON que je viens de récuperer de l'appel /ivp/meters/reports

[
    {
        "createdAt": 1737550707,
        "reportType": "production",
        "cumulative": {
            "currW": 523.558,
            "actPower": 523.558,
            "apprntPwr": 567.365,
            "reactPwr": -214.212,
            "whDlvdCum": 13815850.668,
            "whRcvdCum": 13067.428,
            "varhLagCum": 6165659.509,
            "varhLeadCum": 306241.874,
            "vahCum": 18484800.482,
            "rmsVoltage": 236.827,
            "rmsCurrent": 2.395,
            "pwrFactor": 0.94,
            "freqHz": 50.00
        },
        "lines": [
            {
                "currW": 523.558,
                "actPower": 523.558,
                "apprntPwr": 567.365,
                "reactPwr": -214.212,
                "whDlvdCum": 13815850.668,
                "whRcvdCum": 13067.428,
                "varhLagCum": 6165659.509,
                "varhLeadCum": 306241.874,
                "vahCum": 18484800.482,
                "rmsVoltage": 236.827,
                "rmsCurrent": 2.395,
                "pwrFactor": 0.94,
                "freqHz": 50.00
            }
        ]
    },
    {
        "createdAt": 1737550707,
        "reportType": "net-consumption",
        "cumulative": {
            "currW": 23.232,
            "actPower": 23.232,
            "apprntPwr": 576.017,
            "reactPwr": -493.243,
            "whDlvdCum": 32391896.002,
            "whRcvdCum": 0.000,
            "varhLagCum": 31755.973,
            "varhLeadCum": 27283502.610,
            "vahCum": 50961905.342,
            "rmsVoltage": 236.952,
            "rmsCurrent": 2.431,
            "pwrFactor": 0.04,
            "freqHz": 50.00
        },
        "lines": [
            {
                "currW": 23.232,
                "actPower": 23.232,
                "apprntPwr": 576.017,
                "reactPwr": -493.243,
                "whDlvdCum": 32391896.002,
                "whRcvdCum": 0.000,
                "varhLagCum": 31755.973,
                "varhLeadCum": 27283502.610,
                "vahCum": 50961905.342,
                "rmsVoltage": 236.952,
                "rmsCurrent": 2.431,
                "pwrFactor": 0.04,
                "freqHz": 50.00
            }
        ]
    },
    {
        "createdAt": 1737550707,
        "reportType": "total-consumption",
        "cumulative": {
            "currW": 546.790,
            "actPower": 546.790,
            "apprntPwr": 1143.620,
            "reactPwr": -707.455,
            "whDlvdCum": 46207069.983,
            "whRcvdCum": 0.000,
            "varhLagCum": -6133903.536,
            "varhLeadCum": 26977260.736,
            "vahCum": 50961905.342,
            "rmsVoltage": 236.952,
            "rmsCurrent": 4.826,
            "pwrFactor": 0.48,
            "freqHz": 50.00
        },
        "lines": [
            {
                "currW": 546.790,
                "actPower": 546.790,
                "apprntPwr": 1143.620,
                "reactPwr": -707.455,
                "whDlvdCum": 46207069.983,
                "whRcvdCum": 0.000,
                "varhLagCum": -6133903.536,
                "varhLeadCum": 26977260.736,
                "vahCum": 50961905.342,
                "rmsVoltage": 236.952,
                "rmsCurrent": 4.826,
                "pwrFactor": 0.48,
                "freqHz": 50.00
            }
        ]
    }
]

Bien à toi,
Xtof

@XavierBerger XavierBerger added enhancement New feature or request question Further information is requested labels Jan 26, 2025
@Chilgl0rd
Copy link
Author

Salut Xavier,

J'espère que tu vas bien. Tu veux que j'essaie de coder l'usage du login/pwd pour générer le token et l'utiliser ensuite pour aller chercher les données sur la passerelle ?

Bien à toi,
Xtof

@XavierBerger
Copy link
Owner

Hello,

Si tu veux, c'est avec plaisir que j'intègrerai ton code. Tu peux prendre le lead sur ce dev et je pourrais t'accompagner si tu veux.

J'ai demandé à une IA comment fonctionnaient ces tokens. Sa réponse est que pour l'utilisateur, il est valable 1 an (12 heures pour un installateur).

Donc en termes d’architecture, je proposerais de mettre à jour le certificat au démarrage de l'ESP. Il y a des mises à jour régulières de ESPHome donc pas la peine de se prendre la tête pour le renouvellement. A chaque mise à jour, le certificat sera renouvelé.
Pour le dev, je pense que tu peux t'inspirer du power-meter Fronius.

Pour l'instant, je me concentre sur des MR de nouveaux moteurs incluant de bypass. J'aurai un peu plus de temps à consacrer à Enphase quand ce sera mergé.

N'hésite pas à utiliser l'IA pour ton dev. Même si le code proposé n'est pas toujours fonctionnel, ça donne de bonnes pistes.

@Chilgl0rd
Copy link
Author

Ok ! J'essaie d'avancer ! Ca fait un moment que je n'ai pas codé mais c'est l'occasion de m'y remettre (surtout en Python, j'ai plutôt fait du C/C++). Entre la doc que j'ai, ton exemple et celui de F1ATB, Ca devrait être faisable.
Tu as raison, si on renouvelle au démarrage, ca suffit amplement ! C'est rare d'avoir un uptime si long ;-)

Bien à toi,
Xtof

@Chilgl0rd
Copy link
Author

Chilgl0rd commented Mar 9, 2025

Salut Xavier ! J'espère que tu vas bien.
Désolé pour mon retour tardif mais j'avais pas mal de choses entre temps :-/
Alors j'ai regardé l'état de l'art et différents codes.

J'ai trouvé des choses intéressantes sur https://mesgeekeries.ch/2024/02/03/enphase-demystifier-les-api-locales-avec-des-projets-open-source-en-python/ qui se base sur la bibilothèque https://pyenphase.readthedocs.io/en/latest/ qui, à priori, est à la base du module "officiel" Enphase sur Home Assistant.

si tu l'inclues avec un pip install pyenphase, tu peux l'utiliser et ca réduit considérablement le code et ca gère les différentes versions de firmware

import pyenphase
import asyncio

from pyenphase import Envoy, EnvoyData

async def main():
    envoy = Envoy("Envoy.local")

    await envoy.setup()
    print(f'Envoy {envoy.host} running {envoy.firmware}, sn: {envoy.serial_number}')

    username = "trop@cool.com"
    password = "monBeauMotdePassetRopbien!"

    await envoy.authenticate(username=username, password=password)

    await envoy.probe()

    data = await envoy.update()

    print(f'Production: {data.system_production.watts_now}')
    print(f'Consumption: {data.system_consumption.watts_now}')

asyncio.run(main())

Une fois la partie authentification faite, il faut juste boucler sur l'update et décupérer les 2 valeurs.

Avec ce code, on à juste à renseigner 3 valeurs:
IP locale de la passerelle, login et pwd

J'ai testé chez moi et ca me retour bien les valeurs attendues.

Bien à toi,
Xtof

@Chilgl0rd
Copy link
Author

Après, la valeur qui serait la plus appropriée à monitorer serait "data.ctmeter_consumption.active_power" qui donne le flux entre le réseau et la maison (négatif lorsque l'on que l'on ne produit pas ou plus de batterie)

@XavierBerger
Copy link
Owner

Aller, commençons le développement du power meter pour les onduleurs Enphase? 😄

Je viens de créer une branche dédiée feature/enphase_envoy.

Premier objectif, récupérer le token

@Chilgl0rd, peux-tu tester ?

J'ai créé un exemple : esp32-s3-power-meter-proxy.yaml) dans une branche dédiée (cf.: ref dans la configuration).
J'utilise le nouveau format de configuration où les variables substitution sont replacées par les vars des packages.
Il faudra que tu adaptes ton code en conséquence.

Pour l'instant, j'essaye de récupérer le token sur le site d'Enphase. Si tout se passe bien, tu devrais voir apparaître les 10 premiers caractères du token dans l'interface comme ci dessous (sauf que moi, je n'ai pas de compte... et donc je en peux pas tester et pas de token ):

Image

@Chilgl0rd
Copy link
Author

Chilgl0rd commented Apr 10, 2025

Super 🎉
Alors de viens de copier ton code et changer le user/password dans les vars

J'ai eu un warning à la compîlation:
WARNING` Found 'grant_type=password&username=${enphase_username}&password=MonMotDePasse' (see script->0->then->0->if->then->0->http_request.post->body) which looks like a substitution, but 'enphase_username' was not declared

J'ai donc changé enphase_user par enphase_username dans les vars et ça passe.

Par contre, j'ai toujours plus loin cette erreur:
Compiling` .pioenvs/lctsr02/src/main.cpp.o /data/packages/7fcc7d84/solar_router/power_meter_enphase.yaml: In lambda function: /data/packages/7fcc7d84/solar_router/power_meter_enphase.yaml:54:36: warning: overflow in conversion from 'float' to 'char' changes value from '+QNaNf' to ''\000'' [-Woverflow] id(enphase_token) = NAN; ^~~ /data/packages/7fcc7d84/solar_router/power_meter_enphase.yaml:66:38: warning: overflow in conversion from 'float' to 'char' changes value from '+QNaNf' to ''\000'' [-Woverflow] id(enphase_token) = NAN; ^~~

Bien à toi,
Xtof

@XavierBerger
Copy link
Owner

Je viens de fixer ces erreurs. Mais à part le enphase_username elles ne doivent pas avoir d'impact sur la récupération du token puisque qu'elles concernent justement les cas d'erreur.

@Chilgl0rd
Copy link
Author

Alors j'ai relancé l'installation. Pas d'erreurs mais pas de token... Tu veux que je passe le logger sur un niveau en particulier pour avoir plus d'info ?

@Chilgl0rd
Copy link
Author

En passant en Debug, je ne vois rien, tu as mis des traces des différentes étapes ?
Je viens de relire mon exemple de code plus haut. Il faut aussi passer l'IP de la passerelle, peut être forcer la valeur (IP) plutôt que de laisser le mDNS gérer ?

Peut être afficher le Envoy {envoy.host} running {envoy.firmware}, sn: {envoy.serial_number} afin de s'assurer que l'on choppe bien la passerelle avant l'authentification ?

Bien à toi,
Xtof

@XavierBerger
Copy link
Owner

@Chilgl0rd, je viens de modifier mon code. Il y a maintenant un bouton d'ans l'interface pour demander le token (c'est temporaire). Ça permet de capturer les logs plus facilement. Moi, je reçois un (sans surprise) 401 Unauthorised.
À toi de jouer.

Au fait, tu as vu mon MP sur le forum de HACF.fr ?

@Chilgl0rd
Copy link
Author

Chilgl0rd commented Apr 14, 2025

@XavierBerger Salut !
J'ai aussi un 401

Pourtant j'ai bien fait un copier/coller et rererevérifié login/pwd et c'est bon
Peut être les afficher dans le log pour voir si c'est bien ce qui est passé ?

[19:38:29][D][button:010]: 'get_enphase_token' Pressed.
[19:38:31][E][http_request.arduino:119]: HTTP Request failed; URL: https://api.enphaseenergy.com/api/v2/login; Code: 401
[19:38:31][E][component:164]: Component http_request set Error flag: unspecified
[19:38:31][D][http_request.arduino:125]: Content-Length: -1
[19:38:31][W][custom:090]: HTTP Request failed with status: 401
[19:38:32][E][component:176]: Component http_request cleared Error flag
[19:39:06][D][text_sensor:064]: 'Enphase Token': Sending state 'Server acc...'

Tu veux que je teste un CURL directement sur l'API ?

Je n'ai pas regardé hacf.fr, j'ai vais de ce pas ! :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants