Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/docker_feature.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: feature - build image and push
# This workflow builds and pushes a Docker image to GitHub Container Registry.
# It is triggered on pushes to branches other than "main" and "develop", and can also be triggered manually.
# The image is tagged with the branch name of the push event.
# The workflow uses the GITHUB_TOKEN secret for authentication with GitHub Container Registry.

on:
push:
branches-ignore:
- "main"
- "develop"
workflow_dispatch: # allows manual triggering of the workflow

jobs:
publish_image:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Convert repository owner to lowercase
run: echo "owner=$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV

- name: Build image
run: docker build -t ghcr.io/${{ env.owner }}/eos_connect:feature .

# Only run tagging and pushing tasks for "push" events
- name: Log in to GitHub Container Registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin

- name: Tag image with develop version
run: docker tag ghcr.io/${{ env.owner }}/eos_connect:feature ghcr.io/${{ env.owner }}/eos_connect:feature_dev_${{ github.ref_name }}

- name: Push Docker image to GitHub Container Registry
run: |
docker push ghcr.io/${{ env.owner }}/eos_connect:feature_dev_${{ github.ref_name }}
67 changes: 55 additions & 12 deletions src/interfaces/inverter_fronius.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
fork from https://github.com/ohAnd/batcontrol/blob/main/src/batcontrol/inverter/fronius.py
fork from https://github.com/muexxl/batcontrol/blob/main/src/batcontrol/inverter/fronius.py

This module provides a class `FroniusWR` for handling Fronius GEN24 Inverters.
It includes methods for interacting with the inverter's API, managing battery
Expand Down Expand Up @@ -75,6 +75,16 @@ def __init__(self, config: dict) -> None:
self.nonce = 0
self.user = config['user']
self.password = config['password']
self.inverter_sw_revision = {
'major': 0,
'minor': 0,
'patch': 0,
'build': 0
}
self.api_praefix = '' # default empty string
self.__get_current_inverter_sw_version()
self.__set_api_praefix()

self.previous_battery_config = self.get_battery_config()
self.previous_backup_power_config = None
# default values
Expand Down Expand Up @@ -162,7 +172,7 @@ def get_SOC(self):

def get_battery_config(self):
""" Get battery configuration from inverter and keep a backup."""
path = '/config/batteries'
path = self.api_praefix + '/config/batteries'
response = self.send_request(path, auth=True)
if not response:
logger.error(
Expand Down Expand Up @@ -194,7 +204,7 @@ def get_powerunit_config(self, path_version='latest'):
Returns: dict with backup power configuration
"""
if path_version == 'latest':
path = '/config/powerunit'
path = self.api_praefix + '/config/powerunit'
else:
path = '/config/setup/powerunit'

Expand Down Expand Up @@ -226,7 +236,7 @@ def restore_battery_config(self):
raise RuntimeError(
f"Unable to restore settings. Parameter {key} is missing"
)
path = '/config/batteries'
path = self.api_praefix + '/config/batteries'
payload = json.dumps(settings)
logger.info(
'[Inverter] Restoring previous battery configuration: %s ',
Expand Down Expand Up @@ -256,7 +266,7 @@ def set_allow_grid_charging(self, value: bool):
payload = '{"HYB_EVU_CHARGEFROMGRID": true}'
else:
payload = '{"HYB_EVU_CHARGEFROMGRID": false}'
path = '/config/batteries'
path = self.api_praefix + '/config/batteries'
response = self.send_request(
path, method='POST', payload=payload, auth=True)
response_dict = json.loads(response.text)
Expand All @@ -272,7 +282,7 @@ def set_solar_api_active(self, value: bool):
payload = '{"SolarAPIv1Enabled": true}'
else:
payload = '{"SolarAPIv1Enabled": false}'
path = '/config/solar_api'
path = self.api_praefix + '/config/solar_api'
response = self.send_request(
path, method='POST', payload=payload, auth=True)
response_dict = json.loads(response.text)
Expand All @@ -284,7 +294,7 @@ def set_solar_api_active(self, value: bool):

def set_wr_parameters(self, minsoc, maxsoc, allow_grid_charging, grid_power):
"""set power at grid-connection point negative values for Feed-In"""
path = '/config/batteries'
path = self.api_praefix + '/config/batteries'
if not isinstance(allow_grid_charging , bool):
raise RuntimeError(
f'Expected type: bool actual type: {type(allow_grid_charging)}')
Expand Down Expand Up @@ -331,7 +341,7 @@ def set_wr_parameters(self, minsoc, maxsoc, allow_grid_charging, grid_power):

def get_time_of_use(self):
""" Get time of use configuration from inverter and keep a backup."""
response = self.send_request('/config/timeofuse', auth=True)
response = self.send_request(self.api_praefix + '/config/timeofuse', auth=True)
if not response:
return None

Expand Down Expand Up @@ -455,7 +465,7 @@ def set_time_of_use(self, timeofuselist):
}
payload = json.dumps(config)
response = self.send_request(
'/config/timeofuse', method='POST', payload=payload, auth=True
self.api_praefix + '/config/timeofuse', method='POST', payload=payload, auth=True
)
response_dict = json.loads(response.text)
expected_write_successes = ['timeofuse']
Expand Down Expand Up @@ -561,7 +571,7 @@ def __send_one_http_request(self, path, method='GET', payload="",
def login(self):
"""Login to Fronius API"""
logger.debug("[Inverter] Logging in")
path = '/commands/Login'
path = self.api_praefix + '/commands/Login'
self.cnonce = "NaN"
self.ncvalue_num = 1
self.login_attempts = 0
Expand Down Expand Up @@ -593,7 +603,7 @@ def login(self):

def logout(self):
"""Logout from Fronius API"""
path = '/commands/Logout'
path = self.api_praefix + '/commands/Logout'
response = self.send_request(path, auth=True)
if not response:
logger.warning('[Inverter] Logout failed. No response from server')
Expand Down Expand Up @@ -683,7 +693,7 @@ def __set_em(self, mode = None, power = None):
if power is not None:
settings['HYB_EM_POWER'] = power

path = '/config/batteries'
path = self.api_praefix + '/config/batteries'
payload = json.dumps(settings)
logger.info(
'[Inverter] Setting EM mode %s , power %s',
Expand Down Expand Up @@ -721,6 +731,39 @@ def shutdown(self):
self.restore_time_of_use_config()
self.logout()

def __get_current_inverter_sw_version(self):
"""Get the current version of the inverter."""
path = '/status/version'
response = self.send_request(path)
if not response:
logger.error(
'[Inverter] Failed to get current version. Returning default value'
)
return 99.0
result = json.loads(response.text)
version_string = result.get('swrevisions').get('GEN24')
version_parts = version_string.split('-')[0].split('.')
self.inverter_sw_revision = {
'major': int(version_parts[0]),
'minor': int(version_parts[1]),
'patch': int(version_parts[2]),
'build': int(version_string.split('-')[1])
}
logger.info("[Inverter] Current sw revision: %s", self.inverter_sw_revision)
return True

def __set_api_praefix(self):
"""Set the API prefix based on the inverter version."""
if (self.inverter_sw_revision['major'],
self.inverter_sw_revision['minor'],
self.inverter_sw_revision['patch'],
self.inverter_sw_revision['build']) < (1, 36, 5, 1):
self.api_praefix = ''
logger.info("[Inverter] Using API prefix: '%s'", self.api_praefix)
else:
self.api_praefix = '/api'
logger.info("[Inverter] Using API prefix: '%s'", self.api_praefix)
return True
# def activate_mqtt(self, api_mqtt_api):
# """
# Activates MQTT for the inverter.
Expand Down
Loading