diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..70e816d
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,27 @@
+name: ci
+
+on:
+ push:
+
+jobs:
+ docker:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v3
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v3
+ with:
+ username: ${{ vars.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Build and push
+ uses: docker/build-push-action@v6
+ with:
+ platforms: linux/amd64,linux/arm64,linux/arm/v6
+ push: true
+ tags: gbeine/fronius2mqtt:latest
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..c53e7ff
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,10 @@
+FROM python:3-alpine
+
+WORKDIR /fronius2mqtt
+
+COPY requirements.txt ./
+RUN pip install --no-cache-dir -r requirements.txt
+
+COPY fronius2mqtt .
+
+CMD [ "python", "./fronius2mqtt" ]
diff --git a/README.md b/README.md
index aca690f..7daa6dd 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,12 @@ It forwards the data directly to MQTT.
## Install
+### Installation using Docker
+
+docker run -it --rm --name fronius2mqtt -v fronius2mqtt.conf:/etc/fronius2mqtt.conf docker.io/gbeine/fronius2mqtt
+
+### Native installation with Python venv
+
- clone the git repository
- ensure to have Python 3 with venv installed
- run the ```install``` script in the local directory
@@ -21,16 +27,18 @@ Each configuration option is also available as command line argument.
- copy ```fronius2mqtt.conf.example```
- configure as you like
-| option | default | arguments | comment |
-|----------------|--------------------------|---------------------|--------------------------------------------------------------------|
-| mqtt_host | 'localhost' | -m, --mqtt_host | The hostname of the MQTT server. |
-| mqtt_port | 1883 | --mqtt_port | The port of the MQTT server. |
-| mqtt_keepalive | 30 | --mqtt_keepalive | The keep alive interval for the MQTT server connection in seconds. |
-| mqtt_clientid | 'fronius2mqtt' | --mqtt_clientid | The clientid to send to the MQTT server. |
-| mqtt_user | - | -u, --mqtt_user | The username for the MQTT server connection. |
-| mqtt_password | - | -p, --mqtt_password | The password for the MQTT server connection. |
-| mqtt_topic | 'fronius' | -t, --mqtt_topic | The topic to publish MQTT message. |
-| http_host | 'localhost' | --http_host | The address of the HTTP server. |
-| http_port | 8080 | --http_port | The port of the HTTP server. |
-| verbose | - | -v, --verbose | Be verbose while running. |
-| - | '/etc/fronius2mqtt.conf' | -c, --config | The path to the config file. |
+| option | default | arguments | comment |
+|------------------|--------------------------|---------------------|----------------------------------------------------------------------------------------|
+| mqtt_host | 'localhost' | -m, --mqtt_host | The hostname of the MQTT server. |
+| mqtt_port | 1883 | --mqtt_port | The port of the MQTT server. |
+| mqtt_keepalive | 30 | --mqtt_keepalive | The keep alive interval for the MQTT server connection in seconds. |
+| mqtt_clientid | 'fronius2mqtt' | --mqtt_clientid | The clientid to send to the MQTT server. |
+| mqtt_user | - | -u, --mqtt_user | The username for the MQTT server connection. |
+| mqtt_password | - | -p, --mqtt_password | The password for the MQTT server connection. |
+| mqtt_topic | 'fronius' | -t, --mqtt_topic | The topic to publish MQTT message. |
+| mqtt_tls_version | 'TLSv1.2' | --mqtt_tls_version | The TLS version to use for MQTT. One of TLSv1, TLSv1.1, TLSv1.2. |
+| mqtt_verify_mode | 'CERT_REQUIRED' | --mqtt_verify_mode | The SSL certificate verification mode. One of CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED. |
+| http_host | 'localhost' | --http_host | The address of the HTTP server. |
+| http_port | 8080 | --http_port | The port of the HTTP server. |
+| verbose | - | -v, --verbose | Be verbose while running. |
+| - | '/etc/fronius2mqtt.conf' | -c, --config | The path to the config file. |
diff --git a/fronius2mqtt b/fronius2mqtt
index 28c529f..07f2b24 100755
--- a/fronius2mqtt
+++ b/fronius2mqtt
@@ -2,7 +2,9 @@
import argparse
import json
+import logging
import os
+import ssl
import paho.mqtt.client as mqtt
from bottle import request, route, post, run
@@ -11,6 +13,18 @@ from bottle import request, route, post, run
mqtt_client = None
daemon_args = None
+verify_mode = {
+ 'CERT_NONE': ssl.CERT_NONE,
+ 'CERT_OPTIONAL': ssl.CERT_OPTIONAL,
+ 'CERT_REQUIRED': ssl.CERT_REQUIRED
+}
+
+tls_versions = {
+ 'TLSv1': ssl.PROTOCOL_TLSv1,
+ 'TLSv1.1': ssl.PROTOCOL_TLSv1_1,
+ 'TLSv1.2': ssl.PROTOCOL_TLSv1_2
+}
+
def extract_request_body():
body = request.body
@@ -26,7 +40,7 @@ def extract_request_data():
@route('/')
def index():
- return "Hello World!"
+ return "Hello World!
This is the fronius2mqtt daemon by Gerrit Beine"
@post('/current_data_inverter/')
@@ -162,8 +176,12 @@ def logdata_data(device):
def start_mqtt():
global daemon_args
- mqtt_client = mqtt.Client(daemon_args.mqtt_clientid)
+ mqtt_client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
+ cert_reqs = verify_mode[daemon_args.mqtt_verify_mode] if daemon_args.mqtt_verify_mode in verify_mode else None
+ tls_version = tls_versions[daemon_args.mqtt_tls_version] if daemon_args.mqtt_tls_version in tls_versions else None
+ mqtt_client.tls_set(cert_reqs=cert_reqs,tls_version=tls_version)
if daemon_args.verbose:
+ logging.basicConfig(level=logging.DEBUG)
mqtt_client.enable_logger()
if daemon_args.mqtt_user is not None and daemon_args.mqtt_password is not None:
mqtt_client.username_pw_set(daemon_args.mqtt_user, daemon_args.mqtt_password)
@@ -201,6 +219,21 @@ def parse_args():
parser.add_argument('-t', '--mqtt_topic', type=str,
default='fronius',
help='The topic to publish MQTT message. Default is fronius')
+ parser.add_argument('--mqtt_tls_version', type=str,
+ default='TLSv1.2',
+ help='The TLS version to use for MQTT. One of TLSv1, TLSv1.1, TLSv1.2. Default is TLSv1.2')
+ parser.add_argument('--mqtt_verify_mode', type=str,
+ default='CERT_REQUIRED',
+ help='The SSL certificate verification mode. One of CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED. Default is CERT_REQUIRED')
+ # TODO
+ # parser.add_argument('--mqtt_ca_cert', type=str,
+ # help='The path to the SSL CA certificate. Optional, no default')
+ # parser.add_argument('--mqtt_certfile', type=str,
+ # help='The path to the SSL certificate file. Optional, no default')
+ # parser.add_argument('--mqtt_keyfile', type=str,
+ # help='The path to the SSL key file. Optional, no default')
+ # parser.add_argument('--mqtt_keyfile_password', type=str,
+ # help='The path to the SSL key password. Optional, no default')
parser.add_argument('--http_host', type=str,
default='localhost',
help='The address of the HTTP server. Default is localhost')
@@ -240,6 +273,19 @@ def parse_config():
daemon_args.mqtt_password = data['mqtt_password']
if 'mqtt_topic' in data:
daemon_args.mqtt_topic = data['mqtt_topic']
+ if 'mqtt_tls_version' in data:
+ daemon_args.mqtt_tls_version = data['mqtt_tls_version']
+ if 'mqtt_verify_mode' in data:
+ daemon_args.mqtt_verify_mode = data['mqtt_verify_mode']
+ # TODO
+ # if 'mqtt_ca_cert' in data:
+ # daemon_args.mqtt_ca_cert = data['mqtt_ca_cert']
+ # if 'mqtt_certfile' in data:
+ # daemon_args.mqtt_certfile = data['mqtt_certfile']
+ # if 'mqtt_keyfile' in data:
+ # daemon_args.mqtt_keyfile = data['mqtt_keyfile']
+ # if 'mqtt_keyfile_password' in data:
+ # daemon_args.mqtt_keyfile_password = data['mqtt_keyfile_password']
if 'http_host' in data:
daemon_args.http_host = data['http_host']
if 'http_port' in data: