switch-api 0.6.17__tar.gz → 0.6.19__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {switch_api-0.6.17 → switch_api-0.6.19}/HISTORY.md +14 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/PKG-INFO +38 -6
- switch_api-0.6.19/pyproject.toml +6 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/setup.py +2 -2
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/__init__.py +4 -2
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/realtime/__init__.py +2 -1
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/realtime/_mqtt.py +93 -13
- switch_api-0.6.19/switch_api/realtime/_redis.py +429 -0
- switch_api-0.6.19/switch_api/realtime/realtime.py +397 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api.egg-info/PKG-INFO +39 -7
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api.egg-info/SOURCES.txt +7 -1
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api.egg-info/requires.txt +1 -0
- switch_api-0.6.19/tests/test_dataset.py +7 -0
- switch_api-0.6.19/tests/test_error_handlers.py +196 -0
- switch_api-0.6.19/tests/test_initialize.py +5 -0
- switch_api-0.6.19/tests/test_integration.py +37 -0
- switch_api-0.6.19/tests/test_pipeline.py +6 -0
- switch_api-0.6.17/pyproject.toml +0 -6
- switch_api-0.6.17/switch_api/realtime/realtime.py +0 -235
- {switch_api-0.6.17 → switch_api-0.6.19}/AUTHORS.rst +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/LICENCE +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/MANIFEST.in +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/README.md +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/setup.cfg +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_authentication/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_authentication/_authentication.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_authentication/_credentials_store/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_authentication/_credentials_store/_credentials_store.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_authentication/_msal/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_authentication/_msal/_custom_application.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_compute/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_compute/_commands.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_compute/_compute.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_compute/_iotservice.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_compute/_models.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_compute/_utils.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_guide/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_guide/main.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_guide/processor.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_utils/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_utils/_constants.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_utils/_marketplace.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_utils/_mqtt.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_utils/_platform.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/_utils/_utils.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/analytics/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/analytics/analytics.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/cache/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/cache/cache.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/controls/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/controls/_constants.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/controls/_enums.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/controls/_mqtt.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/controls/controls.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/dataset/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/dataset/dataset.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/email/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/email/email_sender.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/error_handlers/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/error_handlers/error_handlers.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/extensions/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/extensions/extensions.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/extensions/field_meta.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/extensions/helpers.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/extensions/pipeline.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/initialize.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/integration/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/integration/_utils.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/integration/helpers.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/integration/integration.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/pipeline/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/pipeline/automation.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/pipeline/definitions.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/pipeline/pipeline.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/platform_insights/__init__.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api/platform_insights/platform_insights.py +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api.egg-info/dependency_links.txt +0 -0
- {switch_api-0.6.17 → switch_api-0.6.19}/switch_api.egg-info/top_level.txt +0 -0
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# History
|
|
2
2
|
|
|
3
|
+
#0.6.18
|
|
4
|
+
### Changed
|
|
5
|
+
In the `realtime` module:
|
|
6
|
+
- Updated `submit_realtime_updates()` to use the passed `timeout` value when waiting for a retained MQTT message.
|
|
7
|
+
- Added Redis-backed optimistic concurrency support for realtime dataset updates using WATCH/MULTI/EXEC.
|
|
8
|
+
- Added `set_realtime_redis_config()` to configure Redis as the authoritative state store before publishing updates to MQTT.
|
|
9
|
+
- Added `redis` package dependency for Redis-backed realtime state updates.
|
|
10
|
+
- Added a maximum of 3 retained-message subscription attempts for connection or subscribe failures in the MQTT fallback path.
|
|
11
|
+
- Preserved new-topic behavior: when no retained message exists and Redis is not configured, the provided dataframe is used and published as the initial retained dataset.
|
|
12
|
+
- Updated `subscribe_with_retained_sync()` to apply the passed timeout to the MQTT connection, check subscribe failures, and log when no retained topics are received within the wait period.
|
|
13
|
+
- Added Redis timeout retry handling with a default maximum of 3 attempts for Redis realtime update operations.
|
|
14
|
+
- Added MQTT publish reconnect/retry handling for transient `MQTT_ERR_NO_CONN` publish failures.
|
|
15
|
+
|
|
16
|
+
|
|
3
17
|
#0.6.17
|
|
4
18
|
### Changed
|
|
5
19
|
In the `integration` module:
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: switch_api
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.19
|
|
4
4
|
Summary: A complete package for data ingestion into the Switch Automation Platform.
|
|
5
|
-
Home-page: UNKNOWN
|
|
6
5
|
Author: Switch Automation Pty Ltd.
|
|
7
6
|
License: MIT License
|
|
8
|
-
Platform: UNKNOWN
|
|
9
7
|
Classifier: Development Status :: 2 - Pre-Alpha
|
|
10
8
|
Classifier: License :: OSI Approved :: MIT License
|
|
11
9
|
Classifier: Intended Audience :: Other Audience
|
|
@@ -17,6 +15,28 @@ Requires-Python: >=3.8.0
|
|
|
17
15
|
Description-Content-Type: text/markdown
|
|
18
16
|
License-File: LICENCE
|
|
19
17
|
License-File: AUTHORS.rst
|
|
18
|
+
Requires-Dist: pandas==1.5.3
|
|
19
|
+
Requires-Dist: requests
|
|
20
|
+
Requires-Dist: azure-storage-blob
|
|
21
|
+
Requires-Dist: pandera[io]==0.7.1
|
|
22
|
+
Requires-Dist: azure-servicebus
|
|
23
|
+
Requires-Dist: msal>=1.11.0
|
|
24
|
+
Requires-Dist: paho-mqtt==1.6.1
|
|
25
|
+
Requires-Dist: uvicorn==0.22.0
|
|
26
|
+
Requires-Dist: fastapi==0.98.0
|
|
27
|
+
Requires-Dist: pyodbc==4.0.39
|
|
28
|
+
Requires-Dist: cachetools==5.5.0
|
|
29
|
+
Requires-Dist: numexpr==2.10.2
|
|
30
|
+
Requires-Dist: redis<6,>=4.5.5
|
|
31
|
+
Dynamic: author
|
|
32
|
+
Dynamic: classifier
|
|
33
|
+
Dynamic: description
|
|
34
|
+
Dynamic: description-content-type
|
|
35
|
+
Dynamic: license
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
Dynamic: requires-dist
|
|
38
|
+
Dynamic: requires-python
|
|
39
|
+
Dynamic: summary
|
|
20
40
|
|
|
21
41
|
# Switch Automation library for Python
|
|
22
42
|
This is a package for data ingestion into the Switch Automation software platform.
|
|
@@ -38,6 +58,20 @@ pip install switch_api
|
|
|
38
58
|
|
|
39
59
|
# History
|
|
40
60
|
|
|
61
|
+
#0.6.18
|
|
62
|
+
### Changed
|
|
63
|
+
In the `realtime` module:
|
|
64
|
+
- Updated `submit_realtime_updates()` to use the passed `timeout` value when waiting for a retained MQTT message.
|
|
65
|
+
- Added Redis-backed optimistic concurrency support for realtime dataset updates using WATCH/MULTI/EXEC.
|
|
66
|
+
- Added `set_realtime_redis_config()` to configure Redis as the authoritative state store before publishing updates to MQTT.
|
|
67
|
+
- Added `redis` package dependency for Redis-backed realtime state updates.
|
|
68
|
+
- Added a maximum of 3 retained-message subscription attempts for connection or subscribe failures in the MQTT fallback path.
|
|
69
|
+
- Preserved new-topic behavior: when no retained message exists and Redis is not configured, the provided dataframe is used and published as the initial retained dataset.
|
|
70
|
+
- Updated `subscribe_with_retained_sync()` to apply the passed timeout to the MQTT connection, check subscribe failures, and log when no retained topics are received within the wait period.
|
|
71
|
+
- Added Redis timeout retry handling with a default maximum of 3 attempts for Redis realtime update operations.
|
|
72
|
+
- Added MQTT publish reconnect/retry handling for transient `MQTT_ERR_NO_CONN` publish failures.
|
|
73
|
+
|
|
74
|
+
|
|
41
75
|
#0.6.17
|
|
42
76
|
### Changed
|
|
43
77
|
In the `integration` module:
|
|
@@ -1196,5 +1230,3 @@ Removed the `name_as_filename` and `treat_as_timeseries` parameter from the foll
|
|
|
1196
1230
|
- `switch.integration.replace_data()`
|
|
1197
1231
|
- `switch.integration.append_data()`
|
|
1198
1232
|
- `switch.integration.upload_data()`
|
|
1199
|
-
|
|
1200
|
-
|
|
@@ -16,11 +16,11 @@ setup(
|
|
|
16
16
|
long_description_content_type='text/markdown',
|
|
17
17
|
license='MIT License',
|
|
18
18
|
name="switch_api",
|
|
19
|
-
version="0.6.
|
|
19
|
+
version="0.6.19",
|
|
20
20
|
packages=find_packages(include=["switch_api", "switch_api.*"]),
|
|
21
21
|
install_requires=['pandas==1.5.3', 'requests', 'azure-storage-blob', 'pandera[io]==0.7.1', 'azure-servicebus',
|
|
22
22
|
'msal>=1.11.0', 'paho-mqtt==1.6.1', 'uvicorn==0.22.0', 'fastapi==0.98.0', 'pyodbc==4.0.39', 'cachetools==5.5.0',
|
|
23
|
-
'numexpr==2.10.2'],
|
|
23
|
+
'numexpr==2.10.2', 'redis>=4.5.5,<6'],
|
|
24
24
|
python_requires=">=3.8.0",
|
|
25
25
|
classifiers=[
|
|
26
26
|
'Development Status :: 2 - Pre-Alpha',
|
|
@@ -10,7 +10,8 @@ Data Ingestion into the Switch Automation
|
|
|
10
10
|
Complete package for ingestion data into the Switch Automation Platform.
|
|
11
11
|
"""
|
|
12
12
|
__all__ = ['dataset', 'analytics', 'pipeline', 'error_handlers', 'integration',
|
|
13
|
-
'initialize', 'cache', 'extensions', 'email', 'controls', 'realtime', '_compute', 'generate_filepath',
|
|
13
|
+
'initialize', 'cache', 'extensions', 'email', 'controls', 'realtime', '_compute', 'generate_filepath',
|
|
14
|
+
'set_mqtt_broker_config', 'set_realtime_redis_config']
|
|
14
15
|
|
|
15
16
|
from .initialize import initialize
|
|
16
17
|
from . import dataset
|
|
@@ -27,6 +28,7 @@ from . import realtime
|
|
|
27
28
|
from . import _compute
|
|
28
29
|
from ._utils._utils import generate_filepath
|
|
29
30
|
from ._utils._mqtt import set_mqtt_broker_config
|
|
31
|
+
from .realtime import set_realtime_redis_config
|
|
30
32
|
from . import _guide
|
|
31
33
|
|
|
32
34
|
|
|
@@ -42,4 +44,4 @@ from . import _guide
|
|
|
42
44
|
# log.addHandler(_ch)
|
|
43
45
|
# https://dev.to/joaomcteixeira/setting-up-python-logging-for-a-library-app-6ml
|
|
44
46
|
|
|
45
|
-
__version__ = "0.6.
|
|
47
|
+
__version__ = "0.6.19"
|
|
@@ -8,5 +8,6 @@ A module for sending control request of sensors.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from .realtime import submit_realtime_updates
|
|
11
|
+
from ._redis import set_realtime_redis_config
|
|
11
12
|
|
|
12
|
-
__all__ = ['submit_realtime_updates']
|
|
13
|
+
__all__ = ['submit_realtime_updates', 'set_realtime_redis_config']
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
A module containing the SwithRealtime class and associated methods referenced by the controls module in the package. This
|
|
8
8
|
module is not directly referenced by end users.
|
|
9
9
|
"""
|
|
10
|
-
import json
|
|
11
10
|
import logging
|
|
12
11
|
import sys
|
|
13
12
|
import threading
|
|
13
|
+
import time
|
|
14
14
|
from typing import Iterable
|
|
15
15
|
from urllib.parse import urlparse
|
|
16
16
|
import paho.mqtt.client as mqtt
|
|
@@ -68,6 +68,7 @@ class SwitchRealtime:
|
|
|
68
68
|
|
|
69
69
|
self._connected = False
|
|
70
70
|
self._connect_event = threading.Event()
|
|
71
|
+
self._loop_started = False
|
|
71
72
|
|
|
72
73
|
# Store all topic states here
|
|
73
74
|
self.topic_state = {}
|
|
@@ -94,8 +95,13 @@ class SwitchRealtime:
|
|
|
94
95
|
logger.info(f'Attempting connection to MQTT broker with client_id={self.client_id} on host={self.host} port={self.port}')
|
|
95
96
|
logger.info(f'hostname={url.hostname}')
|
|
96
97
|
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
if self._loop_started:
|
|
99
|
+
logger.info("Reconnecting existing MQTT client network loop.")
|
|
100
|
+
self.client.reconnect()
|
|
101
|
+
else:
|
|
102
|
+
self.client.connect(host=url.hostname, port=self.port)
|
|
103
|
+
self.client.loop_start() # Run network loop in background thread
|
|
104
|
+
self._loop_started = True
|
|
99
105
|
|
|
100
106
|
self._connected = self._connect_event.wait(timeout=timeout)
|
|
101
107
|
|
|
@@ -109,8 +115,6 @@ class SwitchRealtime:
|
|
|
109
115
|
if topics is None:
|
|
110
116
|
raise ValueError("topics cannot be None")
|
|
111
117
|
|
|
112
|
-
self.connect()
|
|
113
|
-
|
|
114
118
|
topics = list(topics)
|
|
115
119
|
|
|
116
120
|
if not topics:
|
|
@@ -122,6 +126,11 @@ class SwitchRealtime:
|
|
|
122
126
|
if not isinstance(timeout, int) or timeout <= 0:
|
|
123
127
|
raise ValueError("timeout must be a positive integer")
|
|
124
128
|
|
|
129
|
+
if not self.connect(timeout=timeout):
|
|
130
|
+
raise TimeoutError(
|
|
131
|
+
f"Could not connect to MQTT Broker within {timeout} seconds."
|
|
132
|
+
)
|
|
133
|
+
|
|
125
134
|
# --- Initialize tracking ---
|
|
126
135
|
self._expected_topics = set(topics)
|
|
127
136
|
self._received_retained = set()
|
|
@@ -129,29 +138,100 @@ class SwitchRealtime:
|
|
|
129
138
|
|
|
130
139
|
# --- Subscribe ---
|
|
131
140
|
for topic in topics:
|
|
132
|
-
self.client.subscribe(topic)
|
|
141
|
+
result, _ = self.client.subscribe(topic)
|
|
142
|
+
if result != mqtt.MQTT_ERR_SUCCESS:
|
|
143
|
+
raise RuntimeError(
|
|
144
|
+
f"Failed to subscribe to {topic}. MQTT result code: {result}"
|
|
145
|
+
)
|
|
133
146
|
logger.info(f"Subscribed to = {topic}")
|
|
134
147
|
|
|
135
148
|
# --- Wait until all retained received OR timeout ---
|
|
136
|
-
self._retained_event.wait(timeout=timeout)
|
|
149
|
+
received_all = self._retained_event.wait(timeout=timeout)
|
|
137
150
|
|
|
138
151
|
# --- Return only retained dataset ---
|
|
139
|
-
|
|
152
|
+
retained_dataset = {
|
|
140
153
|
topic: self.topic_state[topic]["payload"]
|
|
141
154
|
for topic in self._received_retained
|
|
142
155
|
if topic in self.topic_state
|
|
143
156
|
}
|
|
144
157
|
|
|
158
|
+
if not received_all:
|
|
159
|
+
missing_topics = self._expected_topics - self._received_retained
|
|
160
|
+
logger.info(
|
|
161
|
+
f"No retained messages received within {timeout} seconds "
|
|
162
|
+
f"for topics: {sorted(missing_topics)}"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
return retained_dataset
|
|
145
166
|
|
|
146
|
-
|
|
167
|
+
|
|
168
|
+
def publish(
|
|
169
|
+
self,
|
|
170
|
+
topic: str,
|
|
171
|
+
payload: str,
|
|
172
|
+
qos: int = 1,
|
|
173
|
+
retain: bool = True,
|
|
174
|
+
timeout: int = WS_MQTT_CONNECTION_TIMEOUT,
|
|
175
|
+
max_retries: int = 3,
|
|
176
|
+
):
|
|
147
177
|
"""
|
|
148
178
|
Publish message to broker.
|
|
149
179
|
Set retain=True to store as last known state.
|
|
150
180
|
"""
|
|
151
|
-
|
|
181
|
+
if not isinstance(max_retries, int) or max_retries < 1:
|
|
182
|
+
raise ValueError("max_retries must be a positive integer.")
|
|
183
|
+
|
|
184
|
+
last_error = None
|
|
185
|
+
|
|
186
|
+
for attempt in range(1, max_retries + 1):
|
|
187
|
+
if not self._connected:
|
|
188
|
+
logger.warning(
|
|
189
|
+
f"MQTT client is not connected before publish to {topic}. "
|
|
190
|
+
f"Reconnect attempt {attempt}/{max_retries}."
|
|
191
|
+
)
|
|
192
|
+
reconnect_error = None
|
|
193
|
+
try:
|
|
194
|
+
connected = self.connect(timeout=timeout)
|
|
195
|
+
except Exception as e:
|
|
196
|
+
connected = False
|
|
197
|
+
reconnect_error = f"Could not reconnect to MQTT Broker: {e}"
|
|
198
|
+
logger.error(reconnect_error)
|
|
199
|
+
|
|
200
|
+
if not connected:
|
|
201
|
+
last_error = reconnect_error or "Could not reconnect to MQTT Broker."
|
|
202
|
+
logger.error(last_error)
|
|
203
|
+
time.sleep(1)
|
|
204
|
+
continue
|
|
205
|
+
|
|
206
|
+
result = self.client.publish(topic, payload, qos=qos, retain=retain)
|
|
207
|
+
|
|
208
|
+
if result.rc == mqtt.MQTT_ERR_SUCCESS:
|
|
209
|
+
logger.info(
|
|
210
|
+
f"MQTT publish accepted for topic={topic}, "
|
|
211
|
+
f"mid={result.mid}, attempt={attempt}/{max_retries}"
|
|
212
|
+
)
|
|
213
|
+
return result
|
|
214
|
+
|
|
215
|
+
last_error = (
|
|
216
|
+
f"Failed to publish to {topic}. MQTT result code: {result.rc}"
|
|
217
|
+
)
|
|
218
|
+
logger.error(last_error)
|
|
219
|
+
|
|
220
|
+
if result.rc != mqtt.MQTT_ERR_NO_CONN or attempt >= max_retries:
|
|
221
|
+
break
|
|
222
|
+
|
|
223
|
+
self._connected = False
|
|
224
|
+
logger.warning(
|
|
225
|
+
f"MQTT publish failed because client is not connected. "
|
|
226
|
+
f"Retrying publish to {topic} after reconnect "
|
|
227
|
+
f"(attempt {attempt + 1}/{max_retries})."
|
|
228
|
+
)
|
|
229
|
+
time.sleep(1)
|
|
230
|
+
|
|
231
|
+
message = last_error or f"Failed to publish to {topic}."
|
|
232
|
+
logger.error(message)
|
|
233
|
+
raise RuntimeError(message)
|
|
152
234
|
|
|
153
|
-
if result.rc != mqtt.MQTT_ERR_SUCCESS:
|
|
154
|
-
logger.error(f"Failed to publish to {topic} : {json.loads(payload)}")
|
|
155
235
|
|
|
156
236
|
|
|
157
237
|
|
|
@@ -202,4 +282,4 @@ class SwitchRealtime:
|
|
|
202
282
|
self._retained_event.set()
|
|
203
283
|
|
|
204
284
|
else:
|
|
205
|
-
logger.info(f'MQTT Message - {topic} : {payload}')
|
|
285
|
+
logger.info(f'MQTT Message - {topic} : {payload}')
|