Compare commits
8 Commits
c332701357
...
v1.0
Author | SHA1 | Date | |
---|---|---|---|
32702c1b0c | |||
03de71fe32 | |||
5d94b00bb1 | |||
df4b62fd47 | |||
53da0a1416 | |||
eb8c865474 | |||
c61fc66c10 | |||
49173dee84 |
3
.env
3
.env
@@ -9,7 +9,7 @@ OPENDTU_ADDR=<ADDRESS OF OPENDTU> # address of opendtu (format: http(s)://<IP-
|
||||
OPENDTU_USER=<OPENDTU USER> # username for opendtu auth
|
||||
OPENDTU_PWD=<OPENDTU PWD> # password for opendtu auth
|
||||
OPENDTU_INVERTER_SN=<SERIAL NR> # serial number of the inverter to control
|
||||
LIMIT_CORRECTION_FACTOR=2 # correction factor for limit setting (e.g.: when only 2 strings of 4 are connected, you always need to set 2x the power), default: 2
|
||||
LIMIT_CORRECTION_FACTOR=2 # correction factor for limit setting (e.g.: when only 2 strings of 4 are connected, you always need to set 2x the power), default: 1.0
|
||||
LIMIT_UPDATE_INTERVAL=5 # interval in which the limit shall be updated, default: 5 [sec]
|
||||
DRY_RUN=0 # if the limit shall be set or not; default: 1 (0: False, 1: True)
|
||||
POWER_TARGET=15 # the target power consumption of the house, default: 50 [Watts]
|
||||
@@ -17,5 +17,4 @@ POWER_TARGET_MIN=0 # minimum percentage for the inverter output
|
||||
POWER_TARGET_MAX=100 # maximum percentage for the inverter output limit, default: 100.0 [%]
|
||||
POWER_DAMPING_FACTOR=0.7 # damping factor for changes of the inverter output limit (between 0-1), default: 0.3
|
||||
POWER_LIMIT_CHANGE_TRESHOLD=0.3 # set a treshold for the api calls: they will not be executed if the new limit isn't that much higher, default: 0.5
|
||||
POWER_LIMIT_TYPE=1 # the power limit type; DON'T CHANGE if you don't know what you're doing, default: 1 (see https://github.com/tbnobody/OpenDTU/discussions/742)
|
||||
PYTHONUNBUFFERED=1 # for use in docker images (for fast logs, ...)
|
||||
|
@@ -2,6 +2,7 @@ FROM python:3.13-slim
|
||||
RUN useradd --create-home --shell /bin/bash solarcontrol
|
||||
WORKDIR /script
|
||||
COPY solarcontrol.py ./
|
||||
RUN pip install --upgrade pip && pip3 install --no-cache-dir paho-mqtt python-dotenv requests
|
||||
RUN pip install --upgrade pip
|
||||
USER solarcontrol
|
||||
ENTRYPOINT ["/usr/bin/python3", "solarcontrol.py"]
|
||||
RUN pip install --user --no-cache-dir paho-mqtt python-dotenv requests
|
||||
CMD ["python", "solarcontrol.py"]
|
||||
|
23
README.md
23
README.md
@@ -1,17 +1,23 @@
|
||||
# SolarControl
|
||||
|
||||
Enforce a zero export (or whatever consumption you like) policy with an OpenDTU-controlled inverter and energy data from MQTT
|
||||
Enforce a zero export (or whatever consumption you like) policy with an OpenDTU-controlled inverter and energy data from MQTT.
|
||||
|
||||
|
||||
## Configuring and usage
|
||||
|
||||
|
||||
### Docker
|
||||
### docker-compose
|
||||
|
||||
Todo
|
||||
To run it using docker, try the `docker-compose.yaml` file present in this repository. You will need the .env file too for that reasons, so the easiest thing is to just run the following commands:
|
||||
|
||||
```bash
|
||||
git clone https://git.privacynerd.de/BlueFox/SolarControl.git && cd SolarControl
|
||||
vi .env # adjust the script to your needs
|
||||
docker-compose up -d && docker-compose logs -f
|
||||
```
|
||||
|
||||
|
||||
### Bare-bone
|
||||
### barebone
|
||||
|
||||
The script can be configured using the .env file where you can adjust it (hopefully perfect) to your needs. After that, just run the script:
|
||||
|
||||
@@ -22,7 +28,12 @@ python3 lge320reader.py
|
||||
Please note: the .env file needs to be in the same folder or any other folder higher up in the directory structure as the script (more specifically, the WORKDIR). It is just a help, actually, the script searches for specific variables in its environment variables. It only loads the .env file so that you do not need to `export` all the files before running (see https://pypi.org/project/python-dotenv/ for more details). This also means that when using it in docker, you can set the docker containers environment file to that .env file and it will be accepted too.
|
||||
|
||||
|
||||
## Building docker
|
||||
## Updating
|
||||
|
||||
To update, simply use `git pull` to pull the latest changes. Afterwards, you need to restart your script (with docker, just use `docker-compose up -d --force-recreate`).
|
||||
|
||||
|
||||
## Building the docker image
|
||||
|
||||
To build the image for docker, simply use the following commands:
|
||||
|
||||
@@ -30,7 +41,7 @@ To build the image for docker, simply use the following commands:
|
||||
docker login # login to docker hub
|
||||
docker buildx create --name buildx-multi-arch
|
||||
docker buildx use buildx-multi-arch
|
||||
docker buildx build --no-cache --platform linux/amd64,linux/386,linux/arm/v5,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -t bluefox42/solarcontrol:<TAGNAME> . --push
|
||||
docker buildx build --no-cache --platform linux/amd64,linux/386,linux/arm/v5,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -t bluefox42/solarcontrol:<VERSION> -t bluefox42/solarcontrol:latest . --push
|
||||
```
|
||||
|
||||
|
||||
|
8
docker-compose.yaml
Normal file
8
docker-compose.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
services:
|
||||
solarcontrol:
|
||||
image: bluefox42/solarcontrol:latest
|
||||
hostname: solarcontrol
|
||||
container_name: solarcontrol
|
||||
env_file: ".env"
|
||||
restart: unless-stopped
|
||||
stop_grace_period: 15s
|
@@ -45,9 +45,12 @@ power_target_min = float(os.getenv('POWER_TARGET_MIN', 0))
|
||||
power_target_max = float(os.getenv('POWER_TARGET_MAX', 100))
|
||||
power_damping_factor = float(os.getenv('POWER_DAMPING_FACTOR', 0.3))
|
||||
power_limit_change_treshold = float(os.getenv('POWER_LIMIT_CHANGE_TRESHOLD', 0.5))
|
||||
power_limit_type = int(os.getenv('POWER_LIMIT_TYPE', 1))
|
||||
dry_run = bool(int(os.getenv('DRY_RUN', 1)))
|
||||
|
||||
# set other important variables
|
||||
power_limit_type = 1 # only set the limit temporary to avoid memory damage; see also: https://github.com/tbnobody/OpenDTU/discussions/742
|
||||
version = "v1.0" # the version number
|
||||
|
||||
# some checks for the correctness of supplied data
|
||||
if power_target_min < 0: power_target_min = 0
|
||||
if power_target_max > 100: power_target_max = 100
|
||||
@@ -55,13 +58,16 @@ if power_damping_factor < 0: power_damping_factor = 0.0
|
||||
if power_damping_factor > 1: power_damping_factor = 1.0
|
||||
|
||||
|
||||
print(f"{bcolors.OKCYAN}Welcome to {bcolors.ENDC}{bcolors.OKBLUE}{bcolors.BOLD}SolarControl{bcolors.ENDC}{bcolors.OKCYAN} ({version})!{bcolors.ENDC}")
|
||||
|
||||
|
||||
# create the powers dict (containing the current use) and data variables (for thread sharing)
|
||||
powers_raw = {"solar": 0, "solar_ts": 0, "house": 0, "house_ts": 0}
|
||||
powers = {"total": None, "total_house": None, "total_solar": None, "timestamp": 0}
|
||||
|
||||
# define mqtt callbacks
|
||||
def on_connect(client, userdata, flags, reason_code, properties):
|
||||
print(f"{bcolors.OKGREEN}Connected with result code {bcolors.ENDC}{reason_code}")
|
||||
print(f"{bcolors.OKGREEN}Connected to the MQTT broker ({mq_broker}:{mq_port}) with result code {bcolors.ENDC}{reason_code}{bcolors.OKGREEN}.{bcolors.ENDC}")
|
||||
client.subscribe("lge320/#")
|
||||
client.subscribe("solar/ac/#")
|
||||
def on_message(client, userdata, msg):
|
||||
@@ -83,6 +89,7 @@ mqttc.connect(mq_broker, mq_port, 60)
|
||||
|
||||
mqttc.loop_start()
|
||||
|
||||
|
||||
def threaded_current_power_calculation():
|
||||
while True:
|
||||
last_powers = powers_raw.copy()
|
||||
|
Reference in New Issue
Block a user