Skip to content
Closed
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
20 changes: 20 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for more information:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
# https://containers.dev/guide/dependabot

version: 2
updates:
- package-ecosystem: "devcontainers"
directory: "/"
schedule:
interval: weekly
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: weekly
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: weekly
34 changes: 31 additions & 3 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Pylint

on:
on:
workflow_dispatch:
push:
branches:
Expand All @@ -13,22 +13,50 @@ on:


jobs:
build:
lint:
runs-on: self-hosted
#runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for all branches

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pylint

- name: Determine base branch and fetch it
run: |
if [ "${{ github.event.pull_request.head.repo.full_name }}" == "${{ github.repository }}" ]; then
BASE_BRANCH="origin/main"
git fetch origin main
else
BASE_BRANCH="upstream/main"
if ! git remote | grep upstream; then
git remote add upstream https://github.com/${{ github.repository_owner }}/${{ github.event.repository.name }}.git
fi
git fetch upstream main
fi
echo "BASE_BRANCH=$BASE_BRANCH" >> $GITHUB_ENV

- name: Get changed files
id: changed-files
run: |
CHANGED_FILES=$(git diff --name-only $BASE_BRANCH...HEAD -- '*.py')
echo "CHANGED_FILES=$CHANGED_FILES" >> $GITHUB_ENV

- name: Analysing the code with pylint
run: |
pylint $(git ls-files '*.py')
for file in ${{ env.CHANGED_FILES }}; do
pylint "$file"
done

3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*.vscode*
*venv*
log
test.py
test*.py
config/batcontrol_config.yaml.bck
run_infinite.sh
debug.txt
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "thermia_online_api"]
path = thermia_online_api
url = https://github.com/hashtagKnorke/thermia-online-api.git
14 changes: 13 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ LABEL maintainer="matthias.strubel@aod-rpg.de"

ENV BATCONTROL_VERSION=${VERSION}
ENV BATCONTROL_GIT_SHA=${GIT_SHA}
# Set default timezone to UTC, override with -e TZ=Europe/Berlin or similar
# when starting the container
# or set the timezone in docker-compose.yml in the environment section,
ENV TZ=UTC

RUN mkdir -p /app /app/logs /app/config
WORKDIR /app
Expand All @@ -19,7 +23,8 @@ RUN apk add --no-cache \
py3-pandas\
py3-yaml\
py3-requests\
py3-paho-mqtt
py3-paho-mqtt \
tzdata


COPY *.py ./
Expand All @@ -32,6 +37,13 @@ COPY inverter ./inverter
COPY forecastconsumption ./forecastconsumption
COPY forecastsolar ./forecastsolar
COPY logfilelimiter ./logfilelimiter
COPY heatpump ./heatpump

# ! module ThermiaOnlineAPI checked out into Git submodule thermia_online_api,
# so we need to copy it to path ThermiaOnlineAPI
# to make it available as Python module on python path
# in the Docker image
COPY thermia_online_api/ThermiaOnlineAPI ./ThermiaOnlineAPI
COPY entrypoint.sh ./
RUN chmod +x entrypoint.sh

Expand Down
83 changes: 83 additions & 0 deletions HOWITWORKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,86 @@ If your consumption exceeds your current production energy from the grid will be
The battery is charged from the grid at a certain charge rate. This mode calculates the estimated required energy for future hours with high electricity prices. The objective is to charge the battery enough so that you do not need to consume energy from the grid in these hours with high prices.
The difference in price is configured with ``min_price_difference``. Charging and Discharging has losses of up to 20%, depending on set-up. This should be considered in the configuration depending on your actual set-up.
How fast the battery can be charged via the grid is defined with the ``max_grid_charge_rate`` configuration. There is a seperate general upper recharge limit is ``max_charging_from_grid_limit``.

## Heatpump integration
### Thermia Heatpump Strategy

The Thermia heat pump integration in this software is designed to optimize the operation of your heat pump based on electricity prices, energy consumption, and energy production forecasts. The strategy aims to minimize energy costs by adjusting the heat pump's operating modes according to predefined rules and configurations.

#### Thermia Online API Extension

The Thermia Online API (https://github.com/klejejs/python-thermia-online-api) has been forked and extended (https://github.com/hashtagKnorke/thermia-online-api/tree/add_calendars) to leverage the Calendar function schedule API of Thermia Online API for setting up the behavior of the Thermia heat pump. This extension allows to control the heat pump based on predefined schedules and energy price forecasts.

##### Integration of the fork
The changes in the fork have been raised as a PR (https://github.com/klejejs/python-thermia-online-api/pull/48) so that they might converge into the mainstream library. For the meantime, the fork has been integrated into the batcontrol repo as a a submodule, integrating the library as sourcecode during dockerfile build.
In case the directory is not in path a small hack in (https://github.com/hashtagKnorke/batcontrol/blob/be5f4eb2df73936234807a4ff355b7d1a9da882e/heatpump/thermia_heatpump.py#L36) tries to add the subdir to the pyton path so that the import succeeds.

##### Key Enhancements

1. **Calendar Function Integration**: The API now supports the Calendar function, enabling users to define and manage schedules for the heat pump's operation. This allows for automated adjustments to the heat pump's modes based on time and energy price forecasts.

2. **Enhanced Scheduling**: Users can create, update, and delete schedules for the heat pump. These schedules can specify different operating modes for different times of the day, optimizing energy usage and cost savings.

##### API Methods

The following methods have been added to the Thermia API to support the Calendar function:

- **get_schedules(installation_id: str)**: Retrieves the schedules for a given installation.
- **add_new_schedule(installation_id: str, data: dict)**: Adds a new schedule for a given installation.
- **delete_schedule(installation_id: str, schedule_id: int)**: Deletes a schedule for a given installation.

These methods allow for full control over the scheduling of the heat pump's operation, enabling users to optimize energy usage and minimize costs effectively.

#### Benefits

- **Cost Savings**: By scheduling the heat pump to operate in energy-saving modes during high price periods, users can significantly reduce their energy costs.
- **Automation**: The integration with the Calendar function allows for automated control of the heat pump, reducing the need for manual adjustments.
- **Flexibility**: Users can define multiple schedules with different operating modes, providing flexibility to adapt to changing energy prices and consumption patterns.

To get started with the extended Thermia Online API, refer to the documentation and configure the necessary settings in the `config/batcontrol_config.yaml` file.

#### Key Components

1. **ThermiaHighPriceHandling**: Manages settings to handle high price periods.
2. **ThermiaStrategySlot**: Represents a strategy decision for a specific time slot.
3. **ThermiaHeatpump**: The main class that manages and controls the Thermia heat pump.

#### Strategy Overview

The strategy involves setting the heat pump to the most energy-saving mode during high price periods while considering the following modes:

- **E: EVU Block**: Activated when electricity prices are high. Maximum energy saving, deactivating heating and Hot water production.
- **B: Hot Water Block**: Activated to block hot water production during high price periods.
- **R: Reduced Heat**: Lowers the heating effect to save energy.
- **N: Normal mode**: No adjustments to heatpump behaviour.
- **H: Increased Heat**: Increases heating when energy is cheap or there is a PV surplus.
- **W: Hot Water Boost**: Boosts hot water production when there is an energy surplus.

#### Configuration Parameters

- **min_price_for_evu_block**: Minimum price to trigger EVU block mode.
- **max_evu_block_hours**: Maximum hours per day for EVU block mode.
- **max_evu_block_duration**: Maximum continuous duration for EVU block mode.
- **min_price_for_hot_water_block**: Minimum price to trigger hot water block mode.
- **max_hot_water_block_hours**: Maximum hours per day for hot water block mode.
- **max_hot_water_block_duration**: Maximum continuous duration for hot water block mode.
- **min_price_for_reduced_heat**: Minimum price to trigger reduced heat mode.
- **max_reduced_heat_hours**: Maximum hours per day for reduced heat mode.
- **max_reduced_heat_duration**: Maximum continuous duration for reduced heat mode.
- **reduced_heat_temperature**: Temperature setting for reduced heat mode.
- **max_price_for_increased_heat**: Maximum price to trigger increased heat mode.
- **min_energy_surplus_for_increased_heat**: Minimum energy surplus to trigger increased heat mode.
- **max_increased_heat_hours**: Maximum hours per day for increased heat mode.
- **max_increased_heat_duration**: Maximum continuous duration for increased heat mode.
- **increased_heat_temperature**: Temperature setting for increased heat mode.
- **max_increased_heat_outdoor_temperature**: Maximum outdoor temperature for increased heat mode.
- **min_energy_surplus_for_hot_water_boost**: Minimum energy surplus to trigger hot water boost mode.
- **max_hot_water_boost_hours**: Maximum hours per day for hot water boost mode.

#### Operation

The software continuously monitors electricity prices, energy consumption, and production forecasts. Based on these inputs and the current state of charge (SOC) of the battery, it dynamically adjusts the heat pump's operating mode to optimize energy usage and minimize costs.

The strategy is recalculated every three minutes to ensure that the heat pump operates in the most cost-effective manner, taking into account the latest forecasts and current conditions.

To configure the Thermia heat pump integration, you will need to adapt the settings in `config/batcontrol_config.yaml`.
37 changes: 35 additions & 2 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ To integrate batcontrol with Home Assistant, use the following repository: [ha_a


## Installation:
(i) This contains some temporary hacky adjustments for Thermia online API integration (see [Thermia API library](https://github.com/hashtagKnorke/batcontrol/blob/be5f4eb2df73936234807a4ff355b7d1a9da882e/HOWITWORKS.md#L38) for details)

## Install:
```sh
git clone https://github.com/muexxl/batcontrol.git
git clone https://github.com/muexxl/batcontrol.git --recurse-submodules
cd batcontrol
virtualenv venv
source venv/bin/activate
Expand All @@ -51,7 +52,6 @@ mkdir -p ./config -p ./logs
- Download the the latest [batcontrol_config.yaml](https://raw.githubusercontent.com/muexxl/batcontrol/refs/heads/main/config/batcontrol_config_dummy.yaml) sample, adjust and place it to config/batcontrol_config.yaml.

- Use the default load_profile (automatically) or create your own.-

### Plain Docker

```
Expand Down Expand Up @@ -80,6 +80,39 @@ services:

Then start the container using `docker-compose up -d`.

### Adjusting Timezone

To adjust the timezone for logging and output, set the `TZ` environment variable.

#### Plain Docker

```
docker run -d \
--name batcontrol \
-v /path/to/config:/app/config \
-v /path/to/logs:/app/logs \
-e TZ=Europe/Berlin \
muexx/batcontrol:latest
```

#### Docker-compose example

Add the `TZ` environment variable to your `docker-compose.yml`:

```
version: '3.8'

services:
batcontrol:
image: muexx/batcontrol:latest
volumes:
- ./config:/app/config
- ./logs:/app/logs
environment:
- TZ=Europe/Berlin
restart: unless-stopped
```

# FAQs

## How are the different config parameters related to each other?
Expand Down
26 changes: 25 additions & 1 deletion batcontrol.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
from dynamictariff import dynamictariff as tariff_factory
from inverter import inverter as inverter_factory
from logfilelimiter import logfilelimiter
from heatpump import heatpump

## Add the subdirectory to the Python path
#sys.path.append(os.path.join(os.path.dirname(__file__), 'thermia_online_api'))


from forecastsolar import solar as solar_factory

Expand Down Expand Up @@ -110,6 +115,9 @@ def __init__(self, configfile):
DELAY_EVALUATION_BY_SECONDS
)

self.inverter = inverter_factory.Inverter.create_inverter(config['inverter'])
self.heatpump = heatpump.Heatpump(config['heatpump'], timezone)

self.inverter = inverter_factory.Inverter.create_inverter(config['inverter'])

self.pvsettings = config['pvinstallations']
Expand Down Expand Up @@ -169,8 +177,14 @@ def __init__(self, configfile):
self.api_set_min_price_difference,
float
)
logger.info(f'[Main] MQTT Callbacks registered ')

# Inverter Callbacks
self.inverter.activate_mqtt(self.mqtt_api)
# Heatpump Callbacks
self.heatpump.activate_mqtt(self.mqtt_api)
logger.info(f'[Main] MQTT Connection to Heatpump ready ')


self.evcc_api = None
if 'evcc' in config.keys():
Expand All @@ -181,12 +195,16 @@ def __init__(self, configfile):
self.evcc_api.register_block_function(self.set_discharge_blocked)
self.evcc_api.wait_ready()
logger.info('[Main] EVCC Connection ready')



def shutdown(self):
logger.info('[Main] Shutting down Batcontrol')
try:
self.inverter.shutdown()
# todo: shutdown other components
del self.inverter
self.heatpump.shutdown()
del self.heatpump
except:
pass

Expand Down Expand Up @@ -430,6 +448,10 @@ def run(self):
datetime.datetime.now().astimezone(self.timezone).minute/60

self.set_wr_parameters(net_consumption, price_dict)
self.heatpump.set_heatpump_parameters(net_consumption, price_dict)

# %%


# %%
def set_wr_parameters(self, net_consumption: np.ndarray, prices: dict):
Expand Down Expand Up @@ -839,6 +861,8 @@ def refresh_static_values(self):
self.mqtt_api.publish_discharge_blocked(self.discharge_blocked)
# Trigger Inverter
self.inverter.refresh_api_values()
if self.heatpump is not None:
self.heatpump.refresh_api_values()

def api_set_mode(self, mode: int):
# Check if mode is valid
Expand Down
20 changes: 20 additions & 0 deletions build_docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/sh

# Get the current commit SHA
GIT_SHA=$(git rev-parse HEAD)

# Get the current Git reference name (branch or tag)
GIT_REF_NAME=$(git symbolic-ref -q --short HEAD || git describe --tags --exact-match)

# Set the VERSION value
if [ -n "$GIT_REF_NAME" ]; then
VERSION=$GIT_REF_NAME
else
VERSION="snapshot"
fi

# Print the VERSION value
echo "SHA: $GIT_SHA .. VERSION: $VERSION"

# Build the Docker image with build arguments
docker buildx build . -t hashtagknorke:batcontrol --build-arg GIT_SHA=$GIT_SHA --build-arg VERSION=$VERSION
Loading