Aller au contenu

Messages recommandés

Posté(e) (modifié)

Bonjour a tous

 

Sur le marketplace il y a un QA pour la gestion des onduleurs fronius

Il est plutôt complet mais perso il me manque une information essentiel

La gestion de la charge ou décharge de la batterie

Cette information est disponible mais le child n'a pas été créer

fronius.png

1179766560_fronius2.png.5e95888f67e5aca03f92ed050c5bac95.png

Comment l'ajouter?

c'est cette info que je voudrais récupérer pour créer le child

 

if self.P_Akku ~= json.null() then 
        self:updateView("akku", "text", "Batterie: - Charge / + Decharge: " .. string.format("%.3f", self.P_Akku) .. " W")
    end

 

J'ai bien réussi a ajouter un child avec cela, mais ma valeur reste a zéro

    -- Current Akku power (w)
    self.P_Akku.currentGridChild = self:initChildDevice("currentAkkuChild", "Akku", "com.fibaro.powerMeter", PowerSensor)

 

 

voici le code

Ci joint l'API de l'onduleur, et a titre d'information ma batterie est une BYD

 

 

-- comment the line below to activate trace logs 
fibaro.trace = function() end

function QuickApp:onInit()
    self:debug('onInit')

    self.E_Total_Consumed = 0
    self.E_Total_Produced = 0

    if (not self:checkConfiguration()) then
        self:updateProperty("log", "Not configured")
        self:warning("Quick app not configured. Please go to the quick app variables configuration, and set ip of your Fronius device.")
    else
        self:updateProperty("log", "")

        self:trace("initFields")
        self:initFields()

        self:trace("createChildDevices")
        self:createChildDevices()

        self:trace("fetchGeneralData")
        self:fetchGeneralData()

        self:trace("fetchMeterData")
        self:fetchMeterData()
    end
end

function QuickApp:checkConfiguration()
    if self:getVariable("ip") ~= "" and self:getVariable("port") ~= "" and self:getVariable("timeout") ~= "" then
        return true
    end

    return false    
end

function QuickApp:initFields()
    self.http = net.HTTPClient({ timeout = 3000 })

    self.ip = self:getVariable("ip")
    self.port = self:getVariable("port")
    self.timeout = tonumber(self:getVariable("timeout"))

    self.childs = {}
    self:updateProperty("configured", true)
end

-- check if provided device id is a child of this quick app
function QuickApp:childDeviceExist(deviceId)
    if deviceId == nil then 
        return false
    end

    local dev = api.get('/devices/' .. tostring(deviceId))

    if dev == nil then
        return false
    end

    return dev.parentId == self.id
end

-- init child devices or create if not exist 
function QuickApp:initChildDevice(variableName, deviceName, type, class)
    local childId = self:getVariable(variableName)

    if(self:childDeviceExist(childId) == false) then
        local child = self:createChildDevice({
            name = deviceName,
            type = type
        }, class)
        childId = child.id
        self:setVariable(variableName, childId)
    
        self:trace(deviceName, "created:", child.id)
    end

    return self.childDevices[childId]
end

function QuickApp:createChildDevices()
    self:initChildDevices({
        ["com.fibaro.electricMeter"] = Meter,
        ["com.fibaro.energyMeter"] = Meter,
        ["com.fibaro.powerMeter"] = PowerSensor,
    })
    
    -- data from: /solar_api/v1/GetMeterRealtimeData.cgi?Scope=System endpoint
    self.childs.totalEnergyConsumedChild = self:initChildDevice("totalEnergyConsumedChild", "Total energy consumed", "com.fibaro.energyMeter", Meter)
    self.childs.totalEnergyConsumedChild:updateProperty("rateType", "consumption")

    -- data from: /solar_api/v1/GetPowerFlowRealtimeData.fcgi endpoint
    -- total energy produced (kWh)
    self.childs.totalEnergyChild = self:initChildDevice("totalEnergyChild", "Total energy produced", "com.fibaro.energyMeter", Meter)
    self.childs.totalEnergyChild:updateProperty("rateType", "production")

    -- total energy produced in a day (kWh)
    -- self.childs.totalEnergyDayChild = self:initChildDevice("totalEnergyDayChild", "Day Consumption", "com.fibaro.electricMeter", Meter)

    -- current production (W)
    self.childs.currentPowerChild = self:initChildDevice("currentPowerChild", "Production", "com.fibaro.powerMeter", PowerSensor)
    self.childs.currentPowerChild:updateProperty("rateType", "production")

    -- current grid power (W)
    -- from docs: value is null if no meter is enabled ( + from grid , - to grid ) 
    self.childs.currentGridChild = self:initChildDevice("currentGridChild", "Grid", "com.fibaro.powerMeter", PowerSensor)
    
    -- self.childs.grid = self:initChildDevice("totalEnergyDayHouseC", "Total energy house day", "com.fibaro.electricMeter", Meter)
end

function QuickApp:setChildVisibility(childName, visible)
    local child = self.childs[childName]

    if child == nil then
        self:warning(string.format("Child %s not found", childName))
        return
    end

    local previousVisible = child:getVariable("visible")

    if previousVisible ~= visible then
        child:setVisible(visible)
        child:setVariable("visible", visible)
        self:debug(string.format("Changing visibility of the child device (id:%d). Visible value: %s", child.id, visible))
    end
end

-- fetch general data 
function QuickApp:fetchGeneralData()
    local requestUrl = string.format("http://%s:%s/solar_api/v1/GetPowerFlowRealtimeData.fcgi", self.ip, self.port)
    self:trace("Sending request:", requestUrl)

    self.http:request(requestUrl, {
        options = {
        method = "GET",
        headers = {
            ["Accept"] = "application/json"
        }
        },
        success = function(response)
            if (response.status == 200) then
                self:updateProperty("log", "")
                self:parseGeneralData(response.data)
            end

            -- loop the request
            fibaro.setTimeout(tonumber(self.timeout) * 1000, function ()
                self:fetchGeneralData()
            end)
        end,
        error = function(err)
            self:error(tostring(err))
            self:updateProperty("log", "Connection error")
            fibaro.setTimeout(tonumber(self.timeout) * 1000, function ()
                self:fetchGeneralData()
            end)
        end
    })
end

function QuickApp:parseGeneralData(data)
    local fronius = json.decode(data)
    self:trace(data)

    self.E_Total = fronius.Body.Data.Site.E_Total or 0  -- total energy produced
    self.P_PV = fronius.Body.Data.Site.P_PV or 0 -- current power
    self.P_Grid = fronius.Body.Data.Site.P_Grid or 0
    self.P_Load = fronius.Body.Data.Site.P_Load or 0
    self.P_Akku = fronius.Body.Data.Site.P_Akku or 0

    self:updateView("mode", "text", "Mode: " .. fronius.Body.Data.Site.Mode)

    if self.P_Grid ~= json.null() then
        self:setChildVisibility("currentGridChild", true)
        self.childs.currentGridChild:updateProperty("log", "")

        local gridValue = string.format("%.0f", self.P_Grid)
        self:updateView("grid", "text", "Linky: - Injection / + Conso: " .. gridValue .. " W")
        self.childs.currentGridChild:setValue(gridValue)

        if self.P_Grid < 0 then
            self.childs.currentGridChild:updateProperty("log", "Injection linky")
        else
            self.childs.currentGridChild:updateProperty("log", "Conso linky")
        end
    else
        self.childs.currentGridChild:updateProperty("log", "Meter not connected")
        self:setChildVisibility("currentGridChild", false) -- hiding unused device
    end
    
    if self.P_Load ~= json.null() then
        self:updateView("load", "text", "Conso maison: " .. string.format("%.3f", self.P_Load) .. " W")
    end

    if self.P_Akku ~= json.null() then 
        self:updateView("akku", "text", "Batterie: - Charge / + Decharge: " .. string.format("%.3f", self.P_Akku) .. " W")
    end

    if self.P_PV ~= json.null() then
        self:updateView("current", "text", "Fronius: " .. string.format("%.3f",self.P_PV) .. " W")
        self.childs.currentPowerChild:updateProperty("value", self.P_PV)
    end

    self:updateView("total", "text", "Index Total: " .. string.format("%.3f",self.E_Total / 1000) .. " kWh")
    self.childs.totalEnergyChild:setValue((self.E_Total) / 1000)

    self:updateView("day", "text", "Index Journaliere: " .. string.format("%.3f",fronius.Body.Data.Site.E_Day / 1000) .. " kWh")
    --self.childs.totalEnergyDayChild:setValue(fronius.Body.Data.Site.E_Day / 1000)

    self:updateView("year", "text", "Index Annuel: " .. string.format("%.3f", fronius.Body.Data.Site.E_Year / 1000) .. " kWh")
end

-- fetch meter data -> not used for now
function QuickApp:fetchMeterData()
    self.http:request("http://" .. self.ip .. ":" .. self.port .. "/solar_api/v1/GetMeterRealtimeData.cgi?Scope=System", {
        options = {
        method = "GET",
        timeout = 10000,
        headers = {
            ["Accept"] = "application/json"
        }
        },
        success = function(response)
            if (response.status == 200) then
                self:parseMeterData(response.data)
            end
            fibaro.setTimeout(tonumber(self.timeout) * 1000, function ()
                self:fetchMeterData()
            end)        
        end,
        error = function(err)
            self:error(tostring(err))
            fibaro.setTimeout(tonumber(self.timeout) * 1000, function ()
            self:fetchMeterData()
        end)        
        end
    })
end

function QuickApp:parseMeterData(data)
    local fronius = json.decode(data)

    if fronius == nil or fronius.Body == nil or fronius.Body.Data["0"] == nil then
        self:trace("Unable to download meter data.")
        self.childs.totalEnergyConsumedChild:updateProperty("log", "Meter not connected")
        self:setChildVisibility("totalEnergyConsumedChild", false) -- hiding unused device
        return
    end

    self.childs.totalEnergyConsumedChild:updateProperty("log", "")
    self:setChildVisibility("totalEnergyConsumedChild", true)

    self.E_Total_Consumed = fronius.Body.Data["0"].EnergyReal_WAC_Sum_Consumed or 0 -- total energy consumed 

    if self.E_Total_Consumed ~= json.null() then
        self:updateView("totalConsumption", "text", "Index Conso Linky Annuel: " .. string.format("%.3f",self.E_Total_Consumed / 1000) .. " kWh")
        self.childs.totalEnergyConsumedChild:setValue((self.E_Total_Consumed) / 1000)
    end

    self.E_Total_Produced = fronius.Body.Data["0"].EnergyReal_WAC_Sum_Produced or 0 -- total energy exported (not used for now)
end

 

API Fronius.pdf

Modifié par flacon030
Posté(e)

Bon je me répond a moi même

Après pas mal d'essais je viens de trouver

Il faut ajouter deux lignes pour ce QA et avoir un nouveau child (celui de la puissance qui entre ou sort de la batterie)

    if self.P_Akku ~= json.null() then 
        self:updateView("akku", "text", "Batterie: - Charge / + Decharge: " .. string.format("%.3f", self.P_Akku) .. " W")
        self.childs.currentAkkuChild:updateProperty("value", self.P_Akku) --  Ligne ajouté Akku
    end
    -- Current Akku power (w)
    self.childs.currentAkkuChild = self:initChildDevice("currentAkkuChild", "Akku", "com.fibaro.powerMeter", PowerSensor) -- ligne ajouter Akku

 

Posté(e)

Un multilevelsensor avec la propriété unit configurée sur % par exemple

Ou alors, tu exploites la propriété batterylevel de l'un des QA existants (parent ou enfant), mais ça ne sera pas très juste, puisque cette propriété, bien que contenant un pourcentage, est censée contenir un niveau de batterie, pas d'autre chose.

Posté(e)

Je pense que je vais essayer un multilevelsensor

Car ce n'est pas une batterie effectivement

C'est le pourcentage d’autoconsommation des PV, rien a voir avec une batterie

 

Merci pour ton aide

Posté(e)

Oui OK.

Sinon c'est un détail ici, mais en PV, le taux d'autoconsommation et le taux d'autonomie sont 2 statistiques bien distinctes.

Posté(e) (modifié)

Oui je vais essayer de remonter ces deux information dans le QA

J'ai vu dans le code json que ces informations sont disponibles

En faite j’essaie de remonter tous les info du code json de l'onduleur et des batteries pour avoir un QA le plus complet possible

Body	
Data	
Inverters	
1	
Battery_Mode	"normal"
DT	99
E_Day	3682
E_Total	3896556
E_Year	1760809.25
P	699
SOC	48.79999923706055
Site	
BatteryStandby	false
E_Day	3682
E_Total	3896556
E_Year	1760809.2000000002
Meter_Location	"grid"
Mode	"bidirectional"
P_Akku	76.86
P_Grid	10.7
P_Load	-709.7
P_PV	670
rel_Autonomy	98.49232069888684
rel_SelfConsumption	100
Version	"12"
Head	
RequestArguments	{}
Status	
Code	0
Reason	""
UserMessage	""
Timestamp	"2023-05-13T12:04:39+02:00"

Il reste un point que j’essaierais de régler plus tard c'est que les child de puissance puissent afficher les puissances comme le child du linky avec la mention "injection" ou "consommation" sous la puissance dans la tuile

 

Modifié par flacon030
Posté(e) (modifié)

J'ai la consommation de mon habitation qui remonte en négatif dans la tuile de mon child et donc invisible sous domocharts

est il possible de la convertir en positif?

    if self.P_Load ~= json.null() then
        self:updateView("load", "text", "Conso maison: " .. string.format("%.3f", self.P_Load) .. " W")
        self.childs.currentLoadChild:updateProperty("value", self.P_Load)
    end

 

Modifié par flacon030
Posté(e)

Si tu veux faire une opération mathématique, il y a plus simple, il suffit de mettre le signe - devant, encore plus efficace que la multiplication.
Mais ces 2 solutions ne sont pas bonnes, car si le nombre est positif, ça donnera un nombre négatif en sortie.
C'est donc bien math.abs() qui renvoie la valeur absolue, donc un nombre positif, en toutes circonstances.
Ou bien si on ne veut pas appeler une fonction externe, on peut le faire avec un simple if pour tester si le nombre est négatif, alors renvoyer -nombre, else renvoyer nombre.

  • Like 1
Posté(e) (modifié)

Effectivement cela fonction en ajoutant * -1 et cela ne posera pas de problème pour cette fonctionnalité vu que la consommation de la maison ne peut pas être négative

 

Mais pour ma culture personnel, je la place ou celle fonction dans mon code?

Merci

fonction math.abs()

code du child

    if self.P_Load ~= json.null() then
        self:updateView("load", "text", "Conso maison: " .. string.format("%.3f", self.P_Load * -1) .. " W")
        self.childs.currentLoadChild:updateProperty("value", self.P_Load * -1)
    end

 

Modifié par flacon030
Posté(e)

C'est très simple

math.abs(-100)

Tu peux remplacer -100 par une variable

 

math.abs(self.P_Load) 


Envoyé de mon BLA-L29 en utilisant Tapatalk

Posté(e) (modifié)

Merci

 

Voici ce que j'obtiens a présent avec ce QA modifier

Reste a réussir a faire fonctionner les deux child "autoconsommation" et "autonomie"

 

224396952_QAfronius.thumb.png.19d49236bb1f595776e4d262d05c3516.png

 

fronius cartouche.png

Modifié par flacon030
Posté(e) (modifié)

bonjour

 

j'essaie de créer mes deux derniers child mais je n'ai aucune valeur qui remonte, elles reste a 0, or elles remonte bien dans mon panneau du QA (voir image ci dessus)

J'ai mis un multilevelSensor avec une propriété en "unit" "%" mais je suis pas sur de faire se qu'il faut

function QuickApp:createChildDevices()
    self:initChildDevices({
	["com.fibaro.multilevelSensor"] = sensor,    
    })

	self.childs.rel_AutonomyChild = self:initChildDevice("rel_AutonomyChild", "rel_Autonomy", "com.fibaro.multilevelSensor", sensor)
    self.childs.rel_AutonomyChild:updateProperty("unit", "%")

    self.childs.rel_SelfConsumptionChild = self:initChildDevice("rel_SelfConsumption", "rel_SelfConsumption", "com.fibaro.multilevelSensor", sensor)
    self.childs.rel_SelfConsumptionChild:updateProperty("unit", "%")  

function QuickApp:parseGeneralData(data)
    local fronius = json.decode(data)
    self:trace(data)

    self.rel_Autonomy = fronius.Body.Data.Site.rel_Autonomy or 0                         
    self.rel_SelfConsumption = fronius.Body.Data.Site.rel_SelfConsumption or 0           
	self:updateView("mode", "text", "Mode: " .. fronius.Body.Data.Site.Mode)

    -- ----rel_SelfConsumption---
    self:updateView("rel_SelfConsumption", "text", "Autoconsommation: " .. string.format("%.3f",fronius.Body.Data.Site.rel_SelfConsumption) .. " %")
    self.childs.rel_SelfConsumption:setValue(fronius.Body.Data.Site.rel_SelfConsumption) 
    -- ----rel_Autonomy---
    self:updateView("rel_Autonomy", "text", "Autonomy: " .. string.format("%.3f",fronius.Body.Data.Site.rel_Autonomy) .. " %")
    self.childs.rel_AutonomyChild:setValue(fronius.Body.Data.Site.rel_Autonomy) 

 

autonomie.png

Modifié par flacon030
Posté(e)

Je vois que tu fais un updateView, pourquoi, tu as un label ?

Si tu veux mettre à jour la propriété value du module, c'est avec updateProperty("value", ma_nouvelle_valeur)

  • 1 mois après...
Posté(e)

My 2 cents sur ce sujet: j'ai aussi du fronius à la maison et arrivera un moment où tu voudras non seulement lire sur ton onduleur mais aussi écrire pour modifier son comportement. Et là, l'API ne pourra rien pour toi car elle ne peut que lire. Tu devras alors passer via Modbus qui a en plus le mérite d'être bien plus complet et rapide. J'ai déjà écrit une QA avec toutes les briques pour exploiter le Modbus Fronius, mais je ne l'ai pas encore publiée car il faut que je la rende plus compréhensible pour les autres. Mais si tu veux partir dans cette voie, je t'aide volontiers car comme le modbus est un protocole super bas niveau (on envoie des messages en hexa, il faut se gaffer avec les conversions de type qu'on recoit en retour et la gestion des nombres négatifs est un grand moment de solitude).

Posté(e)

OK, je vais poser mon QA modbus Fronius ce matin sur Marketplace. Il faut alors bien lire la doc Fronius sur le Modbus (de mémoire, elle n'est pas dispo en téléchargement sur leur site et il faut leur envoyer un mail pour l'obtenir) car des fois, il faut bouger des paramètres obscurs avant que des modifs soient prises en compte, mais la doc a le mérite d'être bien faite. Toute la couche technique de communication a été écrite, l'entier du paramétrage de mon registre y est (= il existe une sorte de structure standardisée pour les onduleurs modbus de toutes marques, mais selon les modèles, tous les registres ne sont pas exploités).

Posté(e) (modifié)

super merci

tiens nous au courant quant elle sera en ligne

Car personnellement se qui me manque est qui n'est pas dans les API c'est le pourcentage de charge batterie

Modifié par flacon030
Posté(e) (modifié)

Bonjour

Je viens de mettre en place ton QA

Merci pour ce dernier

 

Par contre se que je trouve étrange c'est cette valeur

MaxChargingPower: 10240.0 W

Cela correspond a quoi?

 

Se qui serait bien a présent c'est qu'il y est un module enfant pour avoir le % de charge batterie (SOC) afin de pouvoir l'exploiter dans les scenarios de la HC3

Et un retour d'info sur la température de la batterie

Modifié par flacon030
Posté(e)

Concernant le max charging power (et discharge) cela permet de forcer la vitesse de charge/décharge de la batterie stationnaire Fronius, comme dans l’onglet de la gestion de l’énergie, sauf qu’ici, on peut le piloter finement depuis la HC3. Dans mon cas, mon onduleur a une puissance d’ondulation (AC) max de 5.2kW mais mes panneaux peuvent produire jusqu'à 8.2kW (DC). Donc les jours de plein soleil, j’ai intérêt à vider ma batterie sur le réseau en début de journée pour que quand la puissance des panneaux dépasse 5.2kW, l’excédent soit injecté directement dans la batterie qui elle se charge en DC. Sinon, ils sont perdus.

Quand je veux forcer la décharge, je fixe une puissance mini de décharge. Et quand je veux éviter que ma batterie ne se charge trop vite (et ne puisse plus encaisser le surplus de production), je mets une puissance max de charge. Ceci est valable les jours de plein soleil car quand il fait gris, j’ai intérêt à maintenir la batterie totalement chargée. Ca, c’est ce à quoi je veux arriver, ce qui implique d’intégrer dans ma QA non seulement la partie Fronius mais aussi les prévisions météo couplées avec mon capteur de luminosité. Et effectivement, il faudra que je me penche sur la création des enfants pour créer ce qui manque dans le QA Fronius qui utilise l’API et pas le Modbus. Un autre avantage de Modbus, c’est qu’il est possible en un seul appel de récupérer l’entier des paramètres là où via l’API, il faut faire une requête par paramètre. Mais au final, je manque de temps en ce moment pour terminer totalement mon projet. En le rendant public, au moins le boulot de debug (les message d’erreur Modbus sont quasi inutilisables car en gros, il répond juste : « j’ai pas compris » dans le meilleur des cas, voire rien du tout tant que tout n’est pas parfaitement formaté.

Pour la température de la batterie, je n'ai rien trouvé dans les registres de mon onduleur, mais peut être que selon les modèles, c'est dispo. La seul température que j'ai, c'est celle de l'onduleur qui est dans le bloc I160, adresse absolue de registre 42290.

Posté(e) (modifié)

Merci pour toutes ces informations

Vivement le suite

 

Pour info personnellement je suis en batterie BYD HVM de 11,6Kw avec 3Kwc de panneaux et avec un onduleur de 5Kw (fronius Symo hybride)

Je pense que je vais rajouter 1Kwc de panneaux pour avoir la possibilité en été de climatiser la maison, car pour le moment je sui a 93% en autoconsommation et 89% en autosufisance avec le SPA l'eau chaude sanitaire et toute la maison, et les très belle journées avec la climatisation quant la production dépasse les 20Kw/h par jour

 

Modifié par flacon030
×
×
  • Créer...