Skip to content

Commit f14f640

Browse files
authored
Feature/qos config (#19)
* increase version and add QoS default value * add QoS feature and add new link o next version * increase version and implement QoS feature, also move publish code to seaparate fnction and make initialize mqtt connecton as an internal function * increase version and make adjustements to the newly marked internal function
1 parent 9f379f8 commit f14f640

File tree

4 files changed

+70
-32
lines changed

4 files changed

+70
-32
lines changed

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
FROM alpine:3.23.2
22

33
LABEL maintainer="Michael Oberdorf <info@oberdorf-itc.de>"
4-
LABEL site.local.program.version="1.3.4"
4+
LABEL site.local.program.version="1.4.0"
55

66
ENV TZ="UTC" \
77
REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt \
@@ -14,6 +14,7 @@ ENV TZ="UTC" \
1414
MQTT_TLS="false" \
1515
MQTT_TLS_INSECURE="false" \
1616
MQTT_PROTOCOL_VERSION="5" \
17+
MQTT_QOS="0" \
1718
MQTT_TOPIC="com/github/cybcon/docker.weather2mqtt.git/weather" \
1819
MQTT_RETAIN="false" \
1920
CACHE_DIR="/app/cache" \

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ Container image: [DockerHub](https://hub.docker.com/r/oitc/weather2mqtt)
2626

2727
# Supported tags and respective `Dockerfile` links
2828

29-
* [`latest`, `1.3.4`](https://github.com/cybcon/docker.weather2mqtt/blob/v1.3.4/Dockerfile)
29+
* [`latest`, `1.4.0`](https://github.com/cybcon/docker.weather2mqtt/blob/v1.4.0/Dockerfile)
30+
* [`1.3.4`](https://github.com/cybcon/docker.weather2mqtt/blob/v1.3.4/Dockerfile)
3031
* [`1.3.3`](https://github.com/cybcon/docker.weather2mqtt/blob/v1.3.3/Dockerfile)
3132
* [`1.3.1`](https://github.com/cybcon/docker.weather2mqtt/blob/v1.3.1/Dockerfile)
3233
* [`1.3.0`](https://github.com/cybcon/docker.weather2mqtt/blob/v1.3.0/Dockerfile)
@@ -151,6 +152,7 @@ The container grab some configuration via environment variables.
151152
| `MQTT_PASSWORD_FILE` | File that contains the password to authenticate to MQTT broker. | optional | |
152153
| `MQTT_SERVER` | MQTT broker hostname to connect to. | optional | `test.mosquitto.org` |
153154
| `MQTT_PORT` | MQTT broker TCP port to connect to. | optional | `1883` |
155+
| `MQTT_QOS` | MQTT quality of service for published messages. | optional | `0` |
154156
| `MQTT_RETAIN` | Publish MQTT message in retain mode fpr persistance. | optional | `false` |
155157
| `MQTT_TOPIC` | The MQTT topic to publish the weather data. | optional | `com/github/cybcon/docker.weather2mqtt.git/weather` |
156158
| `CACHE_DIR` | Directory used for API request caching. | optional | `/app/cache` |

src/app/bin/weather2mqtt.py

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# Author: Michael Oberdorf
1212
# Date: 2025-04-11
1313
# Last modified by: Michael Oberdorf
14-
# Last modified at: 2026-01-11
14+
# Last modified at: 2026-01-18
1515
###############################################################################
1616
"""
1717

@@ -30,7 +30,7 @@
3030
from lib.weather_codes import WeatherCodes
3131
from retry_requests import retry # seeAlso: https://pypi.org/project/retry-requests/
3232

33-
__version__ = "1.3.4"
33+
__version__ = "1.4.0"
3434
__script_path__ = os.path.dirname(__file__)
3535
__config_path__ = os.path.join(os.path.dirname(__script_path__), "etc")
3636
__local_tz__ = pytz.timezone("UTC")
@@ -134,7 +134,7 @@ def load_config_file() -> dict:
134134
return config
135135

136136

137-
def initialize_mqtt_client() -> mqtt.Client:
137+
def __initialize_mqtt_client() -> mqtt.Client:
138138
"""
139139
Initialize the MQTT client with the given configuration from environment.
140140
@@ -174,7 +174,7 @@ def initialize_mqtt_client() -> mqtt.Client:
174174
client.tls_set(
175175
ca_certs=os.environ.get("REQUESTS_CA_BUNDLE"),
176176
cert_reqs=ssl.CERT_NONE,
177-
tls_version=ssl.PROTOCOL_TLS,
177+
tls_version=ssl.PROTOCOL_TLSv1_2,
178178
ciphers=None,
179179
)
180180
client.tls_insecure_set(True)
@@ -183,7 +183,7 @@ def initialize_mqtt_client() -> mqtt.Client:
183183
client.tls_set(
184184
ca_certs=os.environ.get("REQUESTS_CA_BUNDLE"),
185185
cert_reqs=ssl.CERT_REQUIRED,
186-
tls_version=ssl.PROTOCOL_TLS,
186+
tls_version=ssl.PROTOCOL_TLSv1_2,
187187
ciphers=None,
188188
)
189189
client.tls_insecure_set(False)
@@ -338,6 +338,58 @@ def parse_daily_weather(data: any, fields: list = []) -> dict:
338338
return parsed_data
339339

340340

341+
def publish_weather_data(topic: str, payload: dict) -> None:
342+
"""
343+
Publish the weather data to the MQTT broker.
344+
345+
:param topic str: The MQTT topic to publish the weather data to.
346+
:param payload dict: The weather data to publish.
347+
:raise ssl.SSLCertVerificationError: If there is an SSL certificate verification error.
348+
:raise Exception: If the weather data cannot be published.
349+
"""
350+
log.debug(f"Publish weather data to MQTT topic {topic} with payload: {json.dumps(payload)}")
351+
352+
# Initialize MQTT client
353+
client = __initialize_mqtt_client()
354+
log.debug("MQTT client initialized")
355+
356+
log.debug("Connecting to MQTT server {}:{}".format(os.environ.get("MQTT_SERVER"), os.environ.get("MQTT_PORT")))
357+
try:
358+
client.connect(os.environ.get("MQTT_SERVER"), int(os.environ.get("MQTT_PORT")), 60)
359+
except ssl.SSLCertVerificationError as e:
360+
log.error("SSL certificate verification error: {}".format(e))
361+
sys.exit(1)
362+
log.debug("Connected to MQTT server")
363+
364+
mqtt_retain = False
365+
if os.environ.get("MQTT_RETAIN", "false").lower() == "true":
366+
mqtt_retain = True
367+
mqtt_qos = int(os.environ.get("MQTT_QOS", "0"))
368+
if mqtt_qos not in [0, 1, 2]:
369+
log.warning("Invalid MQTT QoS level: {}. Using QoS 0.".format(mqtt_qos))
370+
mqtt_qos = 0
371+
log.debug(
372+
"Publishing weather data to MQTT topic: {}, using retain: {}, qos: {}".format(
373+
os.environ.get("MQTT_TOPIC"), mqtt_retain, mqtt_qos
374+
)
375+
)
376+
377+
result, mid = client.publish(
378+
topic=topic,
379+
payload=json.dumps(payload, ensure_ascii=False),
380+
qos=mqtt_qos,
381+
retain=mqtt_retain,
382+
)
383+
384+
if result != mqtt.MQTT_ERR_SUCCESS:
385+
raise Exception(f"Failed to publish weather data to MQTT topic {topic}. Error code: {result}")
386+
387+
log.debug(f"Published weather data to MQTT topic {topic} with message ID {mid}")
388+
389+
client.disconnect()
390+
log.debug("Disconnected from MQTT server")
391+
392+
341393
"""
342394
###############################################################################
343395
# M A I N
@@ -381,28 +433,11 @@ def parse_daily_weather(data: any, fields: list = []) -> dict:
381433

382434
log.debug("Payload: {}".format(json.dumps(weather_result, ensure_ascii=False)))
383435

384-
# initialize MQTT client and connect to broker
385-
client = initialize_mqtt_client()
386-
log.debug("MQTT client initialized")
387-
log.debug("Connecting to MQTT server {}:{}".format(os.environ.get("MQTT_SERVER"), os.environ.get("MQTT_PORT")))
388-
try:
389-
client.connect(os.environ.get("MQTT_SERVER"), int(os.environ.get("MQTT_PORT")), 60)
390-
except ssl.SSLCertVerificationError as e:
391-
log.error("SSL certificate verification error: {}".format(e))
392-
sys.exit(1)
393-
394-
retain = False
395-
if os.environ.get("MQTT_RETAIN", "false").lower() == "true":
396-
retain = True
397-
log.debug(
398-
"Publishing weather data to MQTT topic: {}, using retain: {}".format(os.environ.get("MQTT_TOPIC"), retain)
399-
)
400-
client.publish(
401-
topic=os.environ.get("MQTT_TOPIC"), payload=json.dumps(weather_result, ensure_ascii=False), qos=0, retain=retain
436+
# Publish weather data
437+
publish_weather_data(
438+
topic=os.environ.get("MQTT_TOPIC"),
439+
payload=weather_result,
402440
)
403441

404-
client.disconnect()
405-
log.debug("Disconnected from MQTT server")
406-
407442
log.info(f"Stop weather2mqtt version {__version__}")
408443
sys.exit(0)

test/test_weather2mqtt.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
Author: Michael Oberdorf
66
Date: 2025-04-13
77
Last modified by: Michael Oberdorf
8-
Last modified at: 2026-01-11
8+
Last modified at: 2026-01-18
99
***************************************************************************
1010
"""
1111

1212
__author__ = "Michael Oberdorf <info@oberdorf-itc.de>"
1313
__status__ = "production"
14-
__date__ = "2026-01-11"
15-
__version_info__ = ("1", "0", "1")
14+
__date__ = "2026-01-18"
15+
__version_info__ = ("1", "0", "2")
1616
__version__ = ".".join(__version_info__)
1717

1818
__all__ = ["TestWeather2Mqtt"]
@@ -23,9 +23,9 @@
2323

2424
import paho.mqtt.client as mqtt
2525

26+
from src.app.bin.weather2mqtt import __initialize_mqtt_client as initialize_mqtt_client
2627
from src.app.bin.weather2mqtt import (
2728
initialize_logger,
28-
initialize_mqtt_client,
2929
load_config_file,
3030
)
3131

0 commit comments

Comments
 (0)