Jump to content
🌟 NEW Shelly Products Reveal Video! 🌟 NEUE Shelly-Produkte-Enthüllungsvideo! 🌟 ×
NOTICE / HINWEIS: iOS 18 Update and Today Widgets ×

Add Fronius inverter and battery to Shelly virtual buttons


Recommended Posts

Maybe you want to integrate your Fronius inverter to your Shelly Cloud, here is the script, but before you have to make 5 virtual buttons:

1. Battery charge level: (type: Text, view: Progress bar) Virtual ID: 201
2. Power: (type Number , View: Label) Virtual ID: 202
3. Grid: (type Number , View: Label) Virtual ID: 203
4. Consumption: (type Number , View: Label) Virtual ID: 204

If your Virtual buttons have otther ID-s, then change the script, and change your Fronius local IP address.

I hope it helps 🙂

 

// Fronius inverter IP address and API endpoint
let inverter_ip = "10.10.40.14"; // Replace with the Fronius inverter IP address
let api_endpoint = "/solar_api/v1/GetPowerFlowRealtimeData.fcgi"; // Fronius API endpoint

// Virtual buttons IDs
let battery_id = 201;
let power_id = 202;
let grid_id = 203;
let consumption_id = 204; // New ID for consumption

// Function to fetch data from Fronius inverter
function fetchInverterData() {
    print("Starting fetchInverterData function");
    
    // URL for the inverter API request
    let url = "http://" + inverter_ip + api_endpoint;

    Shelly.call("HTTP.GET", { url: url }, function (result, error_code, error_message) {
        if (error_code !== 0) {
            print("Error fetching inverter data: " + error_message);
            print("Error code: " + error_code);
        } else {
            print("HTTP GET request successful. Parsing result...");
            try {
                let inverterData = JSON.parse(result.body);
                print("Received data: " + JSON.stringify(inverterData, null, 2));

                // Specific data extraction and conversion to kW with 3 decimal places
                let power = (inverterData.Body.Data.Site.P_PV / 1000).toFixed(3);
                let grid = (inverterData.Body.Data.Site.P_Grid / 1000).toFixed(3);
                let battery_charge = Math.round(inverterData.Body.Data.Inverters["1"].SOC); // Battery state of charge (SOC)
                let consumption = (inverterData.Body.Data.Site.P_Load / 1000).toFixed(3); // Current consumption in kWh

                // Print extracted data
                print("Power: " + power + " kW");
                print("Grid: " + grid + " kW");
                print("Battery Charge: " + battery_charge + " %");
                print("Consumption: " + consumption + " kWh");

                // Update virtual components
                updateVirtualComponent(battery_id, battery_charge);
                updateVirtualComponent(power_id, power);
                updateVirtualComponent(grid_id, grid);
                updateVirtualComponent(consumption_id, consumption);

            } catch (e) {
                print("Error parsing inverter data: " + e.message);
                print("Received data: " + result.body); // Print the actual data received for debugging
            }
        }
    });
}

// Function to update virtual components
function updateVirtualComponent(component_id, value) {
    Shelly.call(
        "Number.Set",
        {
            "id": component_id,
            "value": value
        },
        function(result, error_code, error_message) {
            if (error_code !== 0) {
                print("An error occurred when updating the virtual component: " + error_message);
            } else {
                print("Virtual component successfully updated. ID: " + component_id + ", Value: " + value);
            }
        }
    );
}

// Fetch inverter data every 5 minutes
Timer.set(300000, true, function () {
    print("Timer triggered. Fetching inverter data...");
    fetchInverterData();
});

// Initial fetch to verify script is working
print("Initial fetch to verify script is working...");
fetchInverterData();

 

Link to comment
Share on other sites

Posted (edited)
On 18.7.2024 at 08:45, Alexanderr Adam said:

Do you have an idea how to get the status if the Fronius Inverter is running in Backup Power mode ?

So you don't get the status if the inverter is in Backup Power mode? Or I misunderstood something?

Edited by Gábor Tályai
Link to comment
Share on other sites

Posted (edited)

Ooh 🙂 You want to get the Power Mode status? To see in what Power Mode is in the inverter. Please run this script, when the inverter is in normal mode, and when in backup mode, and we will see, if the code is working correctly.

I checked it in my Fronius Gen24, and it gives back me: Inverter mode: bidirectional (grid or backup) but I cannot set my device to Backup Power mode to test it.

Anyway, here is the code - don't forget to change the IP address of the inverter.

 

// Fronius inverter IP address and API endpoint
let inverter_ip = "10.10.40.14"; // Replace with the Fronius inverter IP address
let api_endpoint = "/solar_api/v1/GetPowerFlowRealtimeData.fcgi"; // Fronius API endpoint

// Function to fetch data from Fronius inverter
function fetchInverterMode() {
    print("Starting fetchInverterMode function");
    
    // URL for the inverter API request
    let url = "http://" + inverter_ip + api_endpoint;

    Shelly.call("HTTP.GET", { url: url }, function (result, error_code, error_message) {
        if (error_code !== 0) {
            print("Error fetching inverter data: " + error_message);
            print("Error code: " + error_code);
        } else {
            print("HTTP GET request successful. Parsing result...");
            try {
                let inverterData = JSON.parse(result.body);
                // Check the mode of the inverter
                let mode = inverterData.Body.Data.Site.Mode; // Assuming the mode is available in this field
                
                if (mode === "bidirectional") {
                    print("Inverter mode: bidirectional (grid or backup)");
                } else if (mode === "grid") {
                    print("Inverter mode: grid");
                } else if (mode === "backup") {
                    print("Inverter mode: backup");
                } else {
                    print("Inverter mode: " + mode);
                }

            } catch (e) {
                print("Error parsing inverter data: " + e.message);
                print("Received data: " + result.body); // Print the actual data received for debugging
            }
        }
    });
}

// Fetch inverter mode every 5 minutes
Timer.set(300000, true, function () {
    print("Timer triggered. Fetching inverter mode...");
    fetchInverterMode();
});

// Initial fetch to verify script is working
print("Initial fetch to verify script is working...");
fetchInverterMode();

 

Edited by Gábor Tályai
spelling
Link to comment
Share on other sites

Cool, thanks.

I modified the script a bit to update an virtual component. My programming skills are very rusty.

I was wondering that boolean virtual component got another 200 id and the value is not getting updated....

 

// Fronius inverter IP address and API endpoint
let inverter_ip = "192.168.178.10"; // Replace with the Fronius inverter IP address
let api_endpoint = "/solar_api/v1/GetPowerFlowRealtimeData.fcgi"; // Fronius API endpoint
let powermode_id = 200;

// Function to fetch data from Fronius inverter
function fetchInverterMode() {
    print("Starting fetchInverterMode function");
    
    // URL for the inverter API request
    let url = "http://" + inverter_ip + api_endpoint;

    Shelly.call("HTTP.GET", { url: url }, function (result, error_code, error_message) {
        if (error_code !== 0) {
            print("Error fetching inverter data: " + error_message);
            print("Error code: " + error_code);
        } else {
            print("HTTP GET request successful. Parsing result...");
            try {
                let inverterData = JSON.parse(result.body);
                // Check the mode of the inverter
                let mode = inverterData.Body.Data.Site.Mode; // Assuming the mode is available in this field
                
                if (mode === "bidirectional") {
                    print("Inverter mode: bidirectional (grid or backup)");
                } else if (mode === "grid") {
                    print("Inverter mode: grid");
                    updateVirtualComponent(powermode_id, false);
                } else if (mode === "backup") {
                    print("Inverter mode: backup");
                    updateVirtualComponent(powermode_id, true);
                } else {
                    print("Inverter mode: " + mode);
                }

            } catch (e) {
                print("Error parsing inverter data: " + e.message);
                print("Received data: " + result.body); // Print the actual data received for debugging
            }
        }
    });
}

// Fetch inverter mode every 5 seconds
Timer.set(5000, true, function () {
    print("Timer triggered. Fetching inverter mode...");
    fetchInverterMode();
});

// Initial fetch to verify script is working
print("Initial fetch to verify script is working...");
fetchInverterMode();

Link to comment
Share on other sites

Modified it to include updatevirtualcomponent, but still not working ... . 😞

 

// Fronius inverter IP address and API endpoint
let inverter_ip = "192.168.178.10"; // Replace with the Fronius inverter IP address
let api_endpoint = "/solar_api/v1/GetPowerFlowRealtimeData.fcgi"; // Fronius API endpoint
let powermode_id = 200;

// Function to fetch data from Fronius inverter
function fetchInverterMode() {
    print("Starting fetchInverterMode function");
    
    // URL for the inverter API request
    let url = "http://" + inverter_ip + api_endpoint;

    Shelly.call("HTTP.GET", { url: url }, function (result, error_code, error_message) {
        if (error_code !== 0) {
            print("Error fetching inverter data: " + error_message);
            print("Error code: " + error_code);
        } else {
            print("HTTP GET request successful. Parsing result...");
            try {
                let inverterData = JSON.parse(result.body);
                // Check the mode of the inverter
                let mode = inverterData.Body.Data.Site.Mode; // Assuming the mode is available in this field
                
                if (mode === "bidirectional") {
                    print("Inverter mode: bidirectional (grid or backup)");
                } else if (mode === "grid") {
                    print("Inverter mode: grid");
                    updateVirtualComponentBoolean(powermode_id, true);
                } else if (mode === "backup") {
                    print("Inverter mode: backup");
                    updateVirtualComponentBoolean(powermode_id, false);
                } else {
                    print("Inverter mode: " + mode);
                }

            } catch (e) {
                print("Error parsing inverter data: " + e.message);
                print("Received data: " + result.body); // Print the actual data received for debugging
            }
        }
    });
}

// Function to update virtual components
function updateVirtualComponentBoolean(component_id, value) {
    Shelly.call(
        "Boolean.Set",
        {
            "id": component_id,
            "value": value
        },
        function(result, error_code, error_message) {
            if (error_code !== 0) {
                print("An error occurred when updating the virtual component: " + error_message);
            } else {
                print("Virtual component successfully updated. ID: " + component_id + ", Value: " + value);
            }
        }
    );
}


// Fetch inverter mode every 5 seconds
Timer.set(5000, true, function () {
    print("Timer triggered. Fetching inverter mode...");
    fetchInverterMode();
});

// Initial fetch to verify script is working
print("Initial fetch to verify script is working...");
fetchInverterMode();

Link to comment
Share on other sites

Posted (edited)

The BackupMode is in the same api endpoint, so you can add your code to the defined places:

//Virtual components
let backupmode_id = 205;

// Specific data extraction...
let backupMode = inverterData.Body.Data.Site.BackupMode;

// Print extracted data to check it in the console
print("Backupmode: " + backupMode);

 // Update virtual components
 updateVirtualComponent(backupmode_id, backupMode);

For me is not working now, but it should. Check it in the console to see if it is true or false, to see if the code is working.

To update the virtual button: maybe there is some problem with the new firmware, because every time I make a new virtual component, then it gets ID:200. Please check it in your side too.

Edited by Gábor Tályai
spelling
Link to comment
Share on other sites

Here is the reworked code:

- Make the virtual components ID and type as in the code, or change the code
- Boolean type's view must be LABEL!
- Number type's unit: kWh (to see the "kWh" in the Shelly app)
- Change your inverter IP address
- Separated functions, you can delete if something is not useful for you

You will get:
- Fronius Backup mode (true/false)
- Grid power
- Load power
- PV power
- Battery SOC
- Energy from/to battery

 

// Fronius inverter IP address and API endpoint
let inverter_ip = "10.10.40.14"; // Replace with the Fronius inverter IP address
let api_endpoint = "/solar_api/v1/GetPowerFlowRealtimeData.fcgi"; // Fronius API endpoint

// Virtual component IDs
let battery_mode_id = 200; // Boolean
let grid_id = 200;         // Number
let load_id = 201;         // Number
let pv_id = 202;           // Number
let soc_id = 203;          // Number
let battery_id = 204;      // Number

// Function to create the URL for the API request
function createURL() {
    return "http://" + inverter_ip + api_endpoint;
}

// Function to handle the HTTP GET call
function httpGetCall(url, callback) {
    Shelly.call("HTTP.GET", { url: url }, function (result, error_code, error_message) {
        if (error_code !== 0) {
            print("Error: " + error_message);
        } else {
            try {
                let data = JSON.parse(result.body);
                callback(data);
            } catch (e) {
                print("Error parsing data: " + e.message);
            }
        }
    });
}

// Function to fetch Battery Mode
function fetchBatteryMode(callback) {
    let url = createURL();
    httpGetCall(url, function (data) {
        let battery_mode = data.Body.Data.Site.BackupMode;
        updateBooleanComponent(battery_mode_id, battery_mode);
        print("Battery Mode: " + battery_mode);
        if (callback) callback();
    });
}

// Function to fetch Grid data
function fetchGrid(callback) {
    let url = createURL();
    httpGetCall(url, function (data) {
        let grid = (data.Body.Data.Site.P_Grid / 1000).toFixed(2);
        updateNumberComponent(grid_id, grid);
        print("Grid: " + grid + " kW");
        if (callback) callback();
    });
}

// Function to fetch Load data
function fetchLoad(callback) {
    let url = createURL();
    httpGetCall(url, function (data) {
        let load = (data.Body.Data.Site.P_Load / 1000).toFixed(2);
        updateNumberComponent(load_id, load);
        print("Load: " + load + " kW");
        if (callback) callback();
    });
}

// Function to fetch PV data
function fetchPV(callback) {
    let url = createURL();
    httpGetCall(url, function (data) {
        let pv = (data.Body.Data.Site.P_PV / 1000).toFixed(2);
        updateNumberComponent(pv_id, pv);
        print("PV: " + pv + " kW");
        if (callback) callback();
    });
}

// Function to fetch SOC data
function fetchSOC(callback) {
    let url = createURL();
    httpGetCall(url, function (data) {
        let soc = Math.round(data.Body.Data.Inverters["1"].SOC);
        updateNumberComponent(soc_id, soc);
        print("SOC: " + soc + " %");
        if (callback) callback();
    });
}

// Function to fetch Battery data
function fetchBattery(callback) {
    let url = createURL();
    httpGetCall(url, function (data) {
        let battery = (data.Body.Data.Site.P_Akku / 1000).toFixed(2);
        updateNumberComponent(battery_id, battery);
        print("Battery: " + battery + " kW");
        if (callback) callback();
    });
}

// Function to update Shelly boolean virtual component
function updateBooleanComponent(component_id, value) {
    Shelly.call(
        "Boolean.Set",
        {
            "id": component_id,
            "value": value
        },
        function(result, error_code, error_message) {
            if (error_code !== 0) {
                print("Error updating boolean component: " + error_message);
            } else {
                print("Boolean component updated. ID: " + component_id + ", Value: " + value);
            }
        }
    );
}

// Function to update Shelly number virtual component
function updateNumberComponent(component_id, value) {
    print("Updating component ID: " + component_id + " with value: " + value);
    Shelly.call(
        "Number.Set",
        {
            "id": component_id,
            "value": value
        },
        function(result, error_code, error_message) {
            if (error_code !== 0) {
                print("Error updating number component: " + error_message);
            } else {
                print("Number component updated. ID: " + component_id + ", Value: " + value);
            }
        }
    );
}

// Sequentially execute all fetch functions
function fetchAllDataSequentially() {
    fetchBatteryMode(function () {
        fetchGrid(function () {
            fetchLoad(function () {
                fetchPV(function () {
                    fetchSOC(function () {
                        fetchBattery();
                    });
                });
            });
        });
    });
}

// Fetch all data every 5 minutes
Timer.set(300000, true, function () {
    fetchAllDataSequentially();
});

// Initial fetch to verify script is working
fetchAllDataSequentially();

Link to comment
Share on other sites

Here is some cool, linkable icon for the Fronius virtual components:
 

https://img.icons8.com/?size=100&id=0lTulS5AIq64&format=png&color=000000
https://img.icons8.com/?size=100&id=E0UwFzCYyf39&format=png&color=000000
https://img.icons8.com/?size=100&id=51369&format=png&color=000000
https://img.icons8.com/?size=100&id=1ltUbDhgx4RV&format=png&color=000000
https://img.icons8.com/?size=100&id=dwzqRjO6XcTN&format=png&color=000000
https://img.icons8.com/?size=100&id=ehpwHqwrNT4b&format=png&color=000000

And the result:

shelly-fronius-virtual-components-icon.thumb.jpg.02ff479d6c5c93806df119afd5435a51.jpg

Link to comment
Share on other sites

6 minutes ago, Alexanderr Adam said:

Wondering why you are doing now individual http requests for each of the 6 value. I am looking for a more frequent update, like every 5 seconds. Isn't that a bit inefficient to query the data 6 times ?

I created separate functions so that if someone doesn't have a battery, they can easily delete the ones they don't need.

Efficiency: does it work? 🙂 Then it’s efficient 🙂 You can safely put them into one function; based on the first code and this, it will be easy to do, at least you'll practice programming 🙂

Link to comment
Share on other sites

16 minutes ago, Alexanderr Adam said:

Cool, the script is working. Many thanks for your supprt. How do you get the virtual components into the app ? Is there a beta for the app ?

Thanks!

Virtual components in the app:
- you can create a Virtual Component group in the local web interface, and add the virtual components. You can sort the components, as you wish.
- simply turn on the button on the cloud app/virtual components tab (group/components). -- but you must toggle this every time, so I recommend to make a virtual group

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Erstelle neue...