tinkerforge-async 1.4.3__py3-none-any.whl → 1.5.1__py3-none-any.whl

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.
@@ -1,2 +1,2 @@
1
1
  # pylint: disable=missing-module-docstring
2
- __version__ = "1.4.3"
2
+ __version__ = "1.5.1"
@@ -15,7 +15,7 @@ from typing import TYPE_CHECKING, AsyncGenerator, Iterable, NamedTuple
15
15
 
16
16
  from .devices import BasicCallbackConfiguration
17
17
  from .devices import BrickletPort as Port
18
- from .devices import DeviceIdentifier, DeviceWithMCU, Event, GetSPITFPErrorCount
18
+ from .devices import DeviceIdentifier, DeviceWithMCU, Event, GetSPITFPBaudrateConfig, GetSPITFPErrorCount
19
19
  from .devices import ThresholdOption as Threshold
20
20
  from .devices import _FunctionID
21
21
  from .ip_connection_helper import pack_payload, unpack_payload
@@ -265,11 +265,6 @@ class GetWifi2MeshAPStatus(NamedTuple):
265
265
  mac_address: tuple[int, int, int, int, int, int]
266
266
 
267
267
 
268
- class GetSPITFPBaudrateConfig(NamedTuple):
269
- enable_dynamic_baudrate: bool
270
- minimum_dynamic_baudrate: int
271
-
272
-
273
268
  class GetProtocol1BrickletName(NamedTuple):
274
269
  protocol_version: int
275
270
  firmware_version: tuple[int, int, int]
@@ -11,7 +11,14 @@ from decimal import Decimal
11
11
  from enum import Enum, unique
12
12
  from typing import TYPE_CHECKING, AsyncGenerator, NamedTuple
13
13
 
14
- from .devices import AdvancedCallbackConfiguration, BrickletWithMCU, DeviceIdentifier, Event, LedConfig
14
+ from .devices import (
15
+ AdvancedCallbackConfiguration,
16
+ BrickletWithMCU,
17
+ DeviceIdentifier,
18
+ Event,
19
+ LedConfig,
20
+ SimpleCallbackConfiguration,
21
+ )
15
22
  from .devices import ThresholdOption as Threshold
16
23
  from .devices import _FunctionID
17
24
  from .ip_connection_helper import pack_payload, unpack_payload
@@ -99,11 +106,6 @@ class GetChannelLEDStatusConfig(NamedTuple):
99
106
  config: ChannelLedStatusConfig
100
107
 
101
108
 
102
- class GetAllVoltagesCallbackConfiguration(NamedTuple):
103
- period: int
104
- value_has_to_change: bool
105
-
106
-
107
109
  class BrickletIndustrialDualAnalogInV2(BrickletWithMCU):
108
110
  """
109
111
  Measures two DC voltages between -35V and +35V with 24bit resolution each
@@ -313,7 +315,7 @@ class BrickletIndustrialDualAnalogInV2(BrickletWithMCU):
313
315
  response_expected=response_expected,
314
316
  )
315
317
 
316
- async def get_all_voltages_callback_configuration(self) -> GetAllVoltagesCallbackConfiguration:
318
+ async def get_all_voltages_callback_configuration(self) -> SimpleCallbackConfiguration:
317
319
  """
318
320
  Returns the callback configuration as set by :func:`Set All Voltages Callback Configuration`.
319
321
 
@@ -322,7 +324,7 @@ class BrickletIndustrialDualAnalogInV2(BrickletWithMCU):
322
324
  _, payload = await self.ipcon.send_request(
323
325
  device=self, function_id=FunctionID.GET_VOLTAGE_CALLBACK_CONFIGURATION, response_expected=True
324
326
  )
325
- return GetAllVoltagesCallbackConfiguration(*unpack_payload(payload, "I !"))
327
+ return SimpleCallbackConfiguration(*unpack_payload(payload, "I !"))
326
328
 
327
329
  async def set_sample_rate(self, rate: _SamplingRate | int, response_expected: bool = True) -> None:
328
330
  """
@@ -10,7 +10,13 @@ from decimal import Decimal
10
10
  from enum import Enum, unique
11
11
  from typing import TYPE_CHECKING, AsyncGenerator, NamedTuple
12
12
 
13
- from .devices import AdvancedCallbackConfiguration, BrickletWithMCU, DeviceIdentifier, Event
13
+ from .devices import (
14
+ AdvancedCallbackConfiguration,
15
+ BrickletWithMCU,
16
+ DeviceIdentifier,
17
+ Event,
18
+ SimpleCallbackConfiguration,
19
+ )
14
20
  from .devices import ThresholdOption as Threshold
15
21
  from .devices import _FunctionID
16
22
  from .ip_connection_helper import pack_payload, unpack_payload
@@ -94,11 +100,6 @@ class GetInputValueCallbackConfiguration(NamedTuple):
94
100
  value_has_to_change: bool
95
101
 
96
102
 
97
- class GetAllInputValueCallbackConfiguration(NamedTuple):
98
- period: int
99
- value_has_to_change: bool
100
-
101
-
102
103
  class GetMonoflop(NamedTuple):
103
104
  value: bool
104
105
  time: int
@@ -329,7 +330,7 @@ class BrickletIO4V2(BrickletWithMCU):
329
330
  response_expected=response_expected,
330
331
  )
331
332
 
332
- async def get_input_value_callback_configuration(self, channel: int) -> GetInputValueCallbackConfiguration:
333
+ async def get_input_value_callback_configuration(self, channel: int) -> SimpleCallbackConfiguration:
333
334
  """
334
335
  Returns the callback configuration for the given channel as set by
335
336
  :func:`Set Input Value Callback Configuration`.
@@ -342,7 +343,7 @@ class BrickletIO4V2(BrickletWithMCU):
342
343
  data=pack_payload((int(channel),), "B"),
343
344
  response_expected=True,
344
345
  )
345
- return GetInputValueCallbackConfiguration(*unpack_payload(payload, "I !"))
346
+ return SimpleCallbackConfiguration(*unpack_payload(payload, "I !"))
346
347
 
347
348
  async def set_all_input_value_callback_configuration(
348
349
  self, period: int = 0, value_has_to_change: bool = False, response_expected: bool = True
@@ -371,7 +372,7 @@ class BrickletIO4V2(BrickletWithMCU):
371
372
  response_expected=response_expected,
372
373
  )
373
374
 
374
- async def get_all_input_value_callback_configuration(self) -> GetAllInputValueCallbackConfiguration:
375
+ async def get_all_input_value_callback_configuration(self) -> SimpleCallbackConfiguration:
375
376
  """
376
377
  Returns the callback configuration as set by
377
378
  :func:`Set All Input Value Callback Configuration`.
@@ -379,7 +380,7 @@ class BrickletIO4V2(BrickletWithMCU):
379
380
  _, payload = await self.ipcon.send_request(
380
381
  device=self, function_id=FunctionID.GET_ALL_INPUT_VALUE_CALLBACK_CONFIGURATION, response_expected=True
381
382
  )
382
- return GetAllInputValueCallbackConfiguration(*unpack_payload(payload, "I !"))
383
+ return SimpleCallbackConfiguration(*unpack_payload(payload, "I !"))
383
384
 
384
385
  async def set_monoflop(self, channel: int, value: bool, time: int, response_expected: bool = True) -> None:
385
386
  """
@@ -0,0 +1,307 @@
1
+ """
2
+ Module for the Tinkerforge Isolator Bricklet
3
+ (https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Isolator.html) implemented using Python asyncio. It does
4
+ the low-level communication with the Tinkerforge ip connection.
5
+ """
6
+ # pylint: disable=duplicate-code # Many sensors of different generations have a similar API
7
+ from __future__ import annotations
8
+
9
+ from enum import Enum, unique
10
+ from typing import TYPE_CHECKING, AsyncGenerator, NamedTuple
11
+
12
+ from .devices import (
13
+ BrickletWithMCU,
14
+ DeviceIdentifier,
15
+ Event,
16
+ GetSPITFPBaudrateConfig,
17
+ GetSPITFPErrorCount,
18
+ SimpleCallbackConfiguration,
19
+ _FunctionID,
20
+ )
21
+ from .ip_connection_helper import base58decode, pack_payload, unpack_payload
22
+
23
+ if TYPE_CHECKING:
24
+ from .ip_connection import IPConnectionAsync
25
+
26
+
27
+ @unique
28
+ class CallbackID(Enum):
29
+ """
30
+ The callbacks available to this bricklet
31
+ """
32
+
33
+ STATISTICS = 9
34
+
35
+
36
+ _CallbackID = CallbackID
37
+
38
+
39
+ @unique
40
+ class FunctionID(_FunctionID):
41
+ """
42
+ The function calls available to this bricklet
43
+ """
44
+
45
+ GET_STATISTICS = 1
46
+ SET_SPITFP_BAUDRATE_CONFIG = 2
47
+ GET_SPITFP_BAUDRATE_CONFIG = 3
48
+ SET_SPITFP_BAUDRATE = 4
49
+ GET_SPITFP_BAUDRATE = 5
50
+ GET_ISOLATOR_SPITFP_ERROR_COUNT = 6
51
+ SET_STATISTICS_CALLBACK_CONFIGURATION = 7
52
+ GET_STATISTICS_CALLBACK_CONFIGURATION = 8
53
+
54
+
55
+ class GetStatistics(NamedTuple):
56
+ messages_from_brick: int
57
+ messages_from_bricklet: int
58
+ connected_bricklet_device_identifier: int
59
+ connected_bricklet_uid: int
60
+
61
+
62
+ class BrickletIsolator(BrickletWithMCU):
63
+ """
64
+ Galvanically isolates the power and data lines of a Bricklet and its Master Brick.
65
+ """
66
+
67
+ DEVICE_IDENTIFIER = DeviceIdentifier.BRICKLET_ISOLATOR
68
+ DEVICE_DISPLAY_NAME = "Isolator Bricklet"
69
+
70
+ # Convenience imports, so that the user does not need to additionally import them
71
+ CallbackID = CallbackID
72
+ FunctionID = FunctionID
73
+
74
+ CALLBACK_FORMATS = {
75
+ CallbackID.STATISTICS: "I I H 8s",
76
+ }
77
+
78
+ SID_TO_CALLBACK = {
79
+ 0: (CallbackID.STATISTICS,),
80
+ }
81
+
82
+ def __init__(self, uid, ipcon: IPConnectionAsync) -> None:
83
+ """
84
+ Creates an object with the unique device ID *uid* and adds it to
85
+ the IP Connection *ipcon*.
86
+ """
87
+ super().__init__(self.DEVICE_DISPLAY_NAME, uid, ipcon)
88
+
89
+ self.api_version = (2, 0, 1)
90
+
91
+ async def get_value(self, sid: int) -> GetStatistics:
92
+ assert sid == 0
93
+
94
+ return await self.get_statistics()
95
+
96
+ async def set_callback_configuration( # pylint: disable=too-many-arguments
97
+ self,
98
+ sid: int,
99
+ period: int = 0,
100
+ value_has_to_change: bool = False,
101
+ response_expected: bool = True,
102
+ ) -> None:
103
+ assert sid == 0
104
+
105
+ await self.set_statistics_callback_configuration(period, value_has_to_change, response_expected)
106
+
107
+ async def get_callback_configuration(self, sid: int) -> SimpleCallbackConfiguration:
108
+ assert sid == 0
109
+
110
+ return await self.get_statistics_callback_configuration()
111
+
112
+ async def get_statistics(self) -> GetStatistics:
113
+ """
114
+ Returns statistics for the Isolator Bricklet.
115
+ """
116
+ _, payload = await self.ipcon.send_request(
117
+ device=self, function_id=FunctionID.GET_STATISTICS, response_expected=True
118
+ )
119
+ (
120
+ messages_from_brick,
121
+ messages_from_bricklet,
122
+ connected_bricklet_device_identifier,
123
+ connected_bricklet_uid,
124
+ ) = unpack_payload(payload, "I I H 8s")
125
+
126
+ return GetStatistics(
127
+ messages_from_brick,
128
+ messages_from_bricklet,
129
+ connected_bricklet_device_identifier,
130
+ base58decode(connected_bricklet_uid),
131
+ )
132
+
133
+ async def set_spitfp_baudrate_config(
134
+ self,
135
+ enable_dynamic_baudrate: bool = True,
136
+ minimum_dynamic_baudrate: int = 400000,
137
+ response_expected: bool = True,
138
+ ) -> None:
139
+ """
140
+ The SPITF protocol can be used with a dynamic baudrate. If the dynamic baudrate is
141
+ enabled, the Isolator Bricklet will try to adapt the baudrate for the communication
142
+ between Bricks and Bricklets according to the amount of data that is transferred.
143
+
144
+ The baudrate for communication config between
145
+ Brick and Isolator Bricklet can be set through the API of the Brick.
146
+
147
+ The baudrate will be increased exponentially if lots of data is sent/received and
148
+ decreased linearly if little data is sent/received.
149
+
150
+ This lowers the baudrate in applications where little data is transferred (e.g.
151
+ a weather station) and increases the robustness. If there is lots of data to transfer
152
+ (e.g. Thermal Imaging Bricklet) it automatically increases the baudrate as needed.
153
+
154
+ In cases where some data has to transferred as fast as possible every few seconds
155
+ (e.g. RS485 Bricklet with a high baudrate but small payload) you may want to turn
156
+ the dynamic baudrate off to get the highest possible performance.
157
+
158
+ The maximum value of the baudrate can be set per port with the function
159
+ :func:`Set SPITFP Baudrate`. If the dynamic baudrate is disabled, the baudrate
160
+ as set by :func:`Set SPITFP Baudrate` will be used statically.
161
+ """
162
+ await self.ipcon.send_request(
163
+ device=self,
164
+ function_id=FunctionID.SET_SPITFP_BAUDRATE_CONFIG,
165
+ data=pack_payload((bool(enable_dynamic_baudrate), int(minimum_dynamic_baudrate)), "! I"),
166
+ response_expected=response_expected,
167
+ )
168
+
169
+ async def get_spitfp_baudrate_config(self) -> GetSPITFPBaudrateConfig:
170
+ """
171
+ Returns the baudrate config, see :func:`Set SPITFP Baudrate Config`.
172
+ """
173
+ _, payload = await self.ipcon.send_request(
174
+ device=self, function_id=FunctionID.GET_SPITFP_BAUDRATE_CONFIG, response_expected=True
175
+ )
176
+ return GetSPITFPBaudrateConfig(*unpack_payload(payload, "! I"))
177
+
178
+ async def set_spitfp_baudrate(self, baudrate: int = 1400000, response_expected: bool = True) -> None:
179
+ """
180
+ Sets the baudrate for the communication between Isolator Bricklet
181
+ and the connected Bricklet. The baudrate for communication between
182
+ Brick and Isolator Bricklet can be set through the API of the Brick.
183
+
184
+ If you want to increase the throughput of Bricklets you can increase
185
+ the baudrate. If you get a high error count because of high
186
+ interference (see :func:`Get SPITFP Error Count`) you can decrease the
187
+ baudrate.
188
+
189
+ If the dynamic baudrate feature is enabled, the baudrate set by this
190
+ function corresponds to the maximum baudrate (see :func:`Set SPITFP Baudrate Config`).
191
+
192
+ Regulatory testing is done with the default baudrate. If CE compatibility
193
+ or similar is necessary in your applications we recommend to not change
194
+ the baudrate.
195
+ """
196
+ await self.ipcon.send_request(
197
+ device=self,
198
+ function_id=FunctionID.SET_SPITFP_BAUDRATE,
199
+ data=pack_payload((int(baudrate),), "I"),
200
+ response_expected=response_expected,
201
+ )
202
+
203
+ async def get_spitfp_baudrate(self) -> int:
204
+ """
205
+ Returns the baudrate, see :func:`Set SPITFP Baudrate`.
206
+ """
207
+ _, payload = await self.ipcon.send_request(
208
+ device=self,
209
+ function_id=FunctionID.GET_SPITFP_BAUDRATE,
210
+ data=pack_payload((), ""),
211
+ response_expected=True,
212
+ )
213
+ return unpack_payload(payload, "I")
214
+
215
+ async def get_isolator_spitfp_error_count(self) -> GetSPITFPErrorCount:
216
+ """
217
+ Returns the error count for the communication between Isolator Bricklet and
218
+ the connected Bricklet. Call :func:`Get SPITFP Error Count` to get the
219
+ error count between Isolator Bricklet and Brick.
220
+
221
+ The errors are divided into
222
+
223
+ * ACK checksum errors,
224
+ * message checksum errors,
225
+ * framing errors and
226
+ * overflow errors.
227
+ """
228
+ _, payload = await self.ipcon.send_request(
229
+ device=self,
230
+ function_id=FunctionID.GET_ISOLATOR_SPITFP_ERROR_COUNT,
231
+ data=pack_payload((), ""),
232
+ response_expected=True,
233
+ )
234
+ return GetSPITFPErrorCount(*unpack_payload(payload, "I I I I"))
235
+
236
+ async def set_statistics_callback_configuration( # pylint: disable=too-many-arguments
237
+ self,
238
+ period: int = 0,
239
+ value_has_to_change: bool = False,
240
+ response_expected=True,
241
+ ) -> None:
242
+ """
243
+ The period is the period with which the :cb:`Statistics`
244
+ callback is triggered periodically. A value of 0 turns the callback off.
245
+
246
+ If the `value has to change`-parameter is set to true, the callback is only
247
+ triggered after the value has changed. If the value didn't change within the
248
+ period, the callback is triggered immediately on change.
249
+
250
+ If it is set to false, the callback is continuously triggered with the period,
251
+ independent of the value.
252
+
253
+ .. versionadded:: 2.0.2$nbsp;(Plugin)
254
+ """
255
+ assert period >= 0
256
+
257
+ await self.ipcon.send_request(
258
+ device=self,
259
+ function_id=FunctionID.SET_STATISTICS_CALLBACK_CONFIGURATION,
260
+ data=pack_payload(
261
+ (
262
+ int(period),
263
+ bool(value_has_to_change),
264
+ ),
265
+ "I !",
266
+ ),
267
+ response_expected=response_expected,
268
+ )
269
+
270
+ async def get_statistics_callback_configuration(self) -> SimpleCallbackConfiguration:
271
+ """
272
+ Returns the callback configuration as set by
273
+ :func:`Set Statistics Callback Configuration`.
274
+
275
+ .. versionadded:: 2.0.2$nbsp;(Plugin)
276
+ """
277
+ _, payload = await self.ipcon.send_request(
278
+ device=self, function_id=FunctionID.GET_STATISTICS_CALLBACK_CONFIGURATION, response_expected=True
279
+ )
280
+ return SimpleCallbackConfiguration(*unpack_payload(payload, "I !"))
281
+
282
+ async def read_events(
283
+ self,
284
+ events: tuple[int | _CallbackID, ...] | list[int | _CallbackID] | None = None,
285
+ sids: tuple[int, ...] | list[int] | None = None,
286
+ ) -> AsyncGenerator[Event, None]:
287
+ registered_events = set()
288
+ if events:
289
+ for event in events:
290
+ registered_events.add(self.CallbackID(event))
291
+ if sids is not None:
292
+ for sid in sids:
293
+ for callback in self.SID_TO_CALLBACK.get(sid, []):
294
+ registered_events.add(callback)
295
+
296
+ if events is None and sids is None:
297
+ registered_events = set(self.CALLBACK_FORMATS.keys())
298
+
299
+ async for header, payload in super()._read_events():
300
+ try:
301
+ function_id = CallbackID(header.function_id)
302
+ except ValueError:
303
+ # Invalid header. Drop the packet.
304
+ continue
305
+ if function_id in registered_events:
306
+ values = unpack_payload(payload, self.CALLBACK_FORMATS[function_id])
307
+ yield Event(self, 0, function_id, GetStatistics(*values))
@@ -33,6 +33,8 @@ class CallbackID(Enum):
33
33
  SENSOR_CONNECTED = 24
34
34
 
35
35
 
36
+ # We need the alias for MyPy type hinting
37
+ # See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
36
38
  _CallbackID = CallbackID
37
39
 
38
40
 
@@ -73,13 +75,15 @@ class LineFilter(Enum):
73
75
  FREQUENCY_60HZ = 1
74
76
 
75
77
 
76
- _LineFilter = LineFilter # We need the alias for MyPy type hinting
78
+ # We need the alias for MyPy type hinting
79
+ # See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
80
+ _LineFilter = LineFilter
77
81
 
78
82
 
79
83
  @unique
80
84
  class WireMode(Enum):
81
85
  """
82
- Select the measurement setup. Use 3 or wires to eliminate most/all of the
86
+ Select the measurement setup. Use 3 or 4 wires to eliminate most/all the
83
87
  resistance of the wire. Use 3 or 4 wire setups when using PT100 and long
84
88
  cables.
85
89
  """
@@ -89,7 +93,9 @@ class WireMode(Enum):
89
93
  WIRE_4 = 4
90
94
 
91
95
 
92
- _WireMode = WireMode # We need the alias for MyPy type hinting
96
+ # We need the alias for MyPy type hinting
97
+ # See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
98
+ _WireMode = WireMode
93
99
 
94
100
 
95
101
  @unique
@@ -102,6 +108,8 @@ class SensorType(Enum):
102
108
  PT_1000 = 1
103
109
 
104
110
 
111
+ # We need the alias for MyPy type hinting
112
+ # See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
105
113
  _SensorType = SensorType
106
114
 
107
115
 
@@ -30,6 +30,8 @@ class CallbackID(Enum):
30
30
  SENSOR_CONNECTED = 18
31
31
 
32
32
 
33
+ # We need the alias for MyPy type hinting
34
+ # See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
33
35
  _CallbackID = CallbackID
34
36
 
35
37
 
@@ -67,7 +69,9 @@ class LineFilter(Enum):
67
69
  FREQUENCY_60HZ = 1
68
70
 
69
71
 
70
- _LineFilter = LineFilter # We need the alias for MyPy type hinting
72
+ # We need the alias for MyPy type hinting
73
+ # See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
74
+ _LineFilter = LineFilter
71
75
 
72
76
 
73
77
  @unique
@@ -82,6 +86,8 @@ class WireMode(Enum):
82
86
  WIRE_4 = 4
83
87
 
84
88
 
89
+ # We need the alias for MyPy type hinting
90
+ # See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
85
91
  _WireMode = WireMode # We need the alias for MyPy type hinting
86
92
 
87
93
 
@@ -95,7 +101,9 @@ class SensorType(Enum):
95
101
  PT_1000 = 1
96
102
 
97
103
 
98
- _SensorType = SensorType # We need the alias for MyPy type hinting
104
+ # We need the alias for MyPy type hinting
105
+ # See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
106
+ _SensorType = SensorType
99
107
 
100
108
 
101
109
  class GetMovingAverageConfiguration(NamedTuple):
@@ -0,0 +1,419 @@
1
+ """
2
+ Module for the Tinkerforge Thermocouple Bricklet 2.0
3
+ (https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Thermocouple_V2.html) implemented using Python asyncio. It does
4
+ the low-level communication with the Tinkerforge ip connection and also handles conversion of raw units to SI units.
5
+ """
6
+ # pylint: disable=duplicate-code # Many sensors of different generations have a similar API
7
+ from __future__ import annotations
8
+
9
+ from decimal import Decimal
10
+ from enum import Enum, unique
11
+ from typing import TYPE_CHECKING, AsyncGenerator, NamedTuple
12
+
13
+ from .devices import AdvancedCallbackConfiguration, BrickletWithMCU, DeviceIdentifier, Event
14
+ from .devices import ThresholdOption as Threshold
15
+ from .devices import _FunctionID
16
+ from .ip_connection_helper import pack_payload, unpack_payload
17
+
18
+ if TYPE_CHECKING:
19
+ from .ip_connection import IPConnectionAsync
20
+
21
+
22
+ @unique
23
+ class CallbackID(Enum):
24
+ """
25
+ The callbacks available to this bricklet
26
+ """
27
+
28
+ TEMPERATURE = 4
29
+ ERROR_STATE = 8
30
+
31
+
32
+ # We need the alias for MyPy type hinting
33
+ # See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
34
+ _CallbackID = CallbackID
35
+
36
+
37
+ @unique
38
+ class FunctionID(_FunctionID):
39
+ """
40
+ The function calls available to this bricklet
41
+ """
42
+
43
+ GET_TEMPERATURE = 1
44
+ SET_TEMPERATURE_CALLBACK_CONFIGURATION = 2
45
+ GET_TEMPERATURE_CALLBACK_CONFIGURATION = 3
46
+ SET_CONFIGURATION = 5
47
+ GET_CONFIGURATION = 6
48
+ GET_ERROR_STATE = 7
49
+
50
+
51
+ @unique
52
+ class Averaging(Enum):
53
+ """
54
+ The number of values averaged before returning the measurement result.
55
+ """
56
+
57
+ AVERAGING_1 = 1
58
+ AVERAGING_2 = 2
59
+ AVERAGING_4 = 4
60
+ AVERAGING_8 = 8
61
+ AVERAGING_16 = 16
62
+
63
+
64
+ # We need the alias for MyPy type hinting
65
+ # See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
66
+ _Averaging = Averaging
67
+
68
+
69
+ @unique
70
+ class SensorType(Enum):
71
+ """
72
+ The type of thermocouple connected to the bricklet.
73
+ """
74
+
75
+ TYPE_B = 0
76
+ TYPE_E = 1
77
+ TYPE_J = 2
78
+ TYPE_K = 3
79
+ TYPE_N = 4
80
+ TYPE_R = 5
81
+ TYPE_S = 6
82
+ TYPE_T = 7
83
+ TYPE_G8 = 8
84
+ TYPE_G32 = 9
85
+
86
+
87
+ # We need the alias for MyPy type hinting
88
+ # See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
89
+ _SensorType = SensorType
90
+
91
+
92
+ class LineFilter(Enum):
93
+ """
94
+ Selects the notch filter to filter out the mains frequency hum
95
+ """
96
+
97
+ FREQUENCY_50HZ = 0
98
+ FREQUENCY_60HZ = 1
99
+
100
+
101
+ # We need the alias for MyPy type hinting
102
+ # See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
103
+ _LineFilter = LineFilter
104
+
105
+
106
+ class GetConfiguration(NamedTuple):
107
+ averaging: Averaging
108
+ sensor_type: SensorType
109
+ filter: LineFilter
110
+
111
+
112
+ class GetErrorState(NamedTuple):
113
+ """
114
+ Tuple that contains the error states of the system. Over-/undervoltage indicates either a voltage above 3.3 V or
115
+ below 0 V and likely a defective thermocouple. An open circuit indicates a missing or defective thermocouple.
116
+ """
117
+
118
+ over_under: bool
119
+ open_circuit: bool
120
+
121
+
122
+ class BrickletThermocoupleV2(BrickletWithMCU):
123
+ """
124
+ Measures temperature with a thermocouple.
125
+ """
126
+
127
+ DEVICE_IDENTIFIER = DeviceIdentifier.BRICKLET_THERMOCOUPLE_V2
128
+ DEVICE_DISPLAY_NAME = "Thermocouple Bricklet 2.0"
129
+
130
+ # Convenience imports, so that the user does not need to additionally import them
131
+ CallbackID = CallbackID
132
+ FunctionID = FunctionID
133
+ ThresholdOption = Threshold
134
+ Averaging = Averaging
135
+ SensorType = SensorType
136
+ LineFilter = LineFilter
137
+
138
+ CALLBACK_FORMATS = {CallbackID.TEMPERATURE: "i", CallbackID.ERROR_STATE: "! !"}
139
+
140
+ SID_TO_CALLBACK = {
141
+ 0: (CallbackID.TEMPERATURE,),
142
+ 1: (CallbackID.ERROR_STATE,),
143
+ }
144
+
145
+ @property
146
+ def sensor_type(self) -> _SensorType:
147
+ """
148
+ Return the type of sensor. Either PT100 oder PT1000 as a SensorType enum.
149
+ """
150
+ return self.__sensor_type
151
+
152
+ @sensor_type.setter
153
+ def sensor_type(self, value: _SensorType):
154
+ if not isinstance(value, SensorType):
155
+ self.__sensor_type: SensorType = SensorType(value)
156
+ else:
157
+ self.__sensor_type = value
158
+
159
+ def __init__(self, uid, ipcon: IPConnectionAsync, sensor_type: _SensorType = SensorType.TYPE_K) -> None:
160
+ """
161
+ Creates an object with the unique device ID *uid* and adds it to
162
+ the IP Connection *ipcon*.
163
+ """
164
+ super().__init__(self.DEVICE_DISPLAY_NAME, uid, ipcon)
165
+
166
+ self.api_version = (2, 0, 0)
167
+ self.sensor_type = sensor_type # Use the setter to automatically convert to enum
168
+
169
+ def __repr__(self) -> str:
170
+ return (
171
+ f"{self.__class__.__module__}.{self.__class__.__qualname__}"
172
+ f"(uid={self.uid}, ipcon={self.ipcon!r}, sensor_type={self.sensor_type})"
173
+ )
174
+
175
+ async def get_value(self, sid: int) -> Decimal | GetErrorState:
176
+ assert sid in (0, 1)
177
+
178
+ if sid == 0:
179
+ return await self.get_temperature()
180
+ if sid == 1:
181
+ return await self.get_error_state()
182
+ raise ValueError(f"Invalid sid: {sid}. sid must be in (0, 1).")
183
+
184
+ async def set_callback_configuration( # pylint: disable=too-many-arguments
185
+ self,
186
+ sid: int,
187
+ period: int = 0,
188
+ value_has_to_change: bool = False,
189
+ option: Threshold | int = Threshold.OFF,
190
+ minimum: float | Decimal | None = None,
191
+ maximum: float | Decimal | None = None,
192
+ response_expected: bool = True,
193
+ ) -> None:
194
+ minimum = Decimal("273.15") if minimum is None else minimum
195
+ maximum = Decimal("273.15") if maximum is None else maximum
196
+
197
+ if sid == 0:
198
+ await self.set_temperature_callback_configuration(
199
+ period, value_has_to_change, option, minimum, maximum, response_expected
200
+ )
201
+
202
+ raise ValueError(f"Invalid sid: {sid}. sid must be in (0, ).")
203
+
204
+ async def get_callback_configuration(self, sid: int) -> AdvancedCallbackConfiguration:
205
+ if sid == 0:
206
+ return await self.get_temperature_callback_configuration()
207
+
208
+ raise ValueError(f"Invalid sid: {sid}. sid must be in (0, ).")
209
+
210
+ async def get_temperature(self) -> Decimal:
211
+ """
212
+ Returns the temperature of the thermocouple. The value is given in °C/100,
213
+ e.g. a value of 4223 means that a temperature of 42.23 °C is measured.
214
+
215
+ If you want to get the temperature periodically, it is recommended
216
+ to use the :cb:`Temperature` callback and set the period with
217
+ :func:`Set Temperature Callback Configuration`.
218
+
219
+ If you want to get the value periodically, it is recommended to use the
220
+ :cb:`Temperature` callback. You can set the callback configuration
221
+ with :func:`Set Temperature Callback Configuration`.
222
+ """
223
+ _, payload = await self.ipcon.send_request(
224
+ device=self, function_id=FunctionID.GET_TEMPERATURE, response_expected=True
225
+ )
226
+ return self.__value_to_si(unpack_payload(payload, "i"))
227
+
228
+ async def set_temperature_callback_configuration( # pylint: disable=too-many-arguments
229
+ self,
230
+ period: int = 0,
231
+ value_has_to_change: bool = False,
232
+ option: Threshold | int = Threshold.OFF,
233
+ minimum: Decimal | int | float = Decimal("273.15"),
234
+ maximum: Decimal | int | float = Decimal("273.15"),
235
+ response_expected=True,
236
+ ) -> None:
237
+ """
238
+ The period is the period with which the :cb:`Temperature` callback is triggered
239
+ periodically. A value of 0 turns the callback off.
240
+
241
+ If the `value has to change`-parameter is set to true, the callback is only
242
+ triggered after the value has changed. If the value didn't change
243
+ within the period, the callback is triggered immediately on change.
244
+
245
+ If it is set to false, the callback is continuously triggered with the period,
246
+ independent of the value.
247
+
248
+ It is furthermore possible to constrain the callback with thresholds.
249
+
250
+ The `option`-parameter together with min/max sets a threshold for the :cb:`Temperature` callback.
251
+
252
+ The following options are possible:
253
+
254
+ .. csv-table::
255
+ :header: "Option", "Description"
256
+ :widths: 10, 100
257
+
258
+ "'x'", "Threshold is turned off"
259
+ "'o'", "Threshold is triggered when the value is *outside* the min and max values"
260
+ "'i'", "Threshold is triggered when the value is *inside* or equal to the min and max values"
261
+ "'<'", "Threshold is triggered when the value is smaller than the min value (max is ignored)"
262
+ "'>'", "Threshold is triggered when the value is greater than the min value (max is ignored)"
263
+
264
+ If the option is set to 'x' (threshold turned off) the callback is triggered with the fixed period.
265
+ """
266
+ if not isinstance(option, Threshold):
267
+ option = Threshold(option)
268
+ assert period >= 0
269
+
270
+ await self.ipcon.send_request(
271
+ device=self,
272
+ function_id=FunctionID.SET_TEMPERATURE_CALLBACK_CONFIGURATION,
273
+ data=pack_payload(
274
+ (
275
+ int(period),
276
+ bool(value_has_to_change),
277
+ option.value.encode("ascii"),
278
+ self.__si_to_value(minimum),
279
+ self.__si_to_value(maximum),
280
+ ),
281
+ "I ! c i i",
282
+ ),
283
+ response_expected=response_expected,
284
+ )
285
+
286
+ async def get_temperature_callback_configuration(self) -> AdvancedCallbackConfiguration:
287
+ """
288
+ Returns the callback configuration as set by :func:`Set Temperature Callback Configuration`.
289
+ """
290
+ _, payload = await self.ipcon.send_request(
291
+ device=self, function_id=FunctionID.GET_TEMPERATURE_CALLBACK_CONFIGURATION, response_expected=True
292
+ )
293
+ period, value_has_to_change, option, minimum, maximum = unpack_payload(payload, "I ! c i i")
294
+ option = Threshold(option)
295
+ minimum, maximum = self.__value_to_si(minimum), self.__value_to_si(maximum)
296
+ return AdvancedCallbackConfiguration(period, value_has_to_change, option, minimum, maximum)
297
+
298
+ async def set_configuration(
299
+ self,
300
+ averaging: _Averaging,
301
+ sensor_type: _SensorType,
302
+ line_filter: _LineFilter,
303
+ response_expected: bool = True,
304
+ ) -> None:
305
+ """
306
+ You can configure averaging size, thermocouple type and frequency
307
+ filtering.
308
+
309
+ Available averaging sizes are 1, 2, 4, 8 and 16 samples.
310
+
311
+ As thermocouple type you can use B, E, J, K, N, R, S and T. If you have a
312
+ different thermocouple or a custom thermocouple you can also use
313
+ G8 and G32. With these types the returned value will not be in °C/100,
314
+ it will be calculated by the following formulas:
315
+
316
+ * G8: ``value = 8 * 1.6 * 2^17 * Vin``
317
+ * G32: ``value = 32 * 1.6 * 2^17 * Vin``
318
+
319
+ where Vin is the thermocouple input voltage.
320
+
321
+ The frequency filter can be either configured to 50Hz or to 60Hz. You should
322
+ configure it according to your utility frequency.
323
+
324
+ The conversion time depends on the averaging and filter configuration, it can
325
+ be calculated as follows:
326
+
327
+ * 60Hz: ``time = 82 + (samples - 1) * 16.67``
328
+ * 50Hz: ``time = 98 + (samples - 1) * 20``
329
+ """
330
+ if not isinstance(averaging, Averaging):
331
+ averaging = Averaging(averaging)
332
+ if not isinstance(sensor_type, SensorType):
333
+ sensor_type = SensorType(sensor_type)
334
+ if not isinstance(line_filter, LineFilter):
335
+ line_filter = LineFilter(line_filter)
336
+
337
+ self.__sensor_type = sensor_type
338
+ await self.ipcon.send_request(
339
+ device=self,
340
+ function_id=FunctionID.SET_CONFIGURATION,
341
+ data=pack_payload((averaging.value, sensor_type.value, line_filter.value), "B B B"),
342
+ response_expected=response_expected,
343
+ )
344
+
345
+ async def get_configuration(self) -> GetConfiguration:
346
+ _, payload = await self.ipcon.send_request(
347
+ device=self, function_id=FunctionID.GET_CONFIGURATION, response_expected=True
348
+ )
349
+
350
+ averaging, sensor_type, line_filter = unpack_payload(payload, "B B B")
351
+ return GetConfiguration(Averaging(averaging), SensorType(sensor_type), LineFilter(line_filter))
352
+
353
+ async def get_error_state(self) -> GetErrorState:
354
+ """
355
+ Returns the current error state. There are two possible errors:
356
+
357
+ * Over/Under Voltage and
358
+ * Open Circuit.
359
+
360
+ Over/Under Voltage happens for voltages below 0V or above 3.3V. In this case
361
+ it is very likely that your thermocouple is defective. An Open Circuit error
362
+ indicates that there is no thermocouple connected.
363
+
364
+ You can use the :cb:`Error State` callback to automatically get triggered
365
+ when the error state changes.
366
+ """
367
+ _, payload = await self.ipcon.send_request(
368
+ device=self, function_id=FunctionID.GET_ERROR_STATE, response_expected=True
369
+ )
370
+
371
+ over_under, open_circuit = unpack_payload(payload, "! !")
372
+ return GetErrorState(over_under, open_circuit)
373
+
374
+ def __value_to_si(self, value: int) -> Decimal:
375
+ """
376
+ Convert to the sensor value to SI units
377
+ """
378
+ if self.__sensor_type is SensorType.TYPE_G8:
379
+ return Decimal(value / 8 / 1.6 / 2**17)
380
+ if self.__sensor_type is SensorType.TYPE_G32:
381
+ return Decimal(value / 8 / 1.6 / 2**17)
382
+ return Decimal(value + 27315) / 100
383
+
384
+ def __si_to_value(self, value: float | Decimal) -> int:
385
+ if self.__sensor_type is SensorType.TYPE_G8:
386
+ return int(float(value) * 8 * 1.6 * 2**17)
387
+ if self.__sensor_type is SensorType.TYPE_G32:
388
+ return int(float(value) * 8 * 1.6 * 2**17)
389
+ return int(value * 100) - 27315
390
+
391
+ async def read_events(
392
+ self,
393
+ events: tuple[int | _CallbackID, ...] | list[int | _CallbackID] | None = None,
394
+ sids: tuple[int, ...] | list[int] | None = None,
395
+ ) -> AsyncGenerator[Event, None]:
396
+ registered_events = set()
397
+ if events:
398
+ for event in events:
399
+ registered_events.add(self.CallbackID(event))
400
+ if sids is not None:
401
+ for sid in sids:
402
+ for callback in self.SID_TO_CALLBACK.get(sid, []):
403
+ registered_events.add(callback)
404
+
405
+ if events is None and sids is None:
406
+ registered_events = set(self.CALLBACK_FORMATS.keys())
407
+
408
+ async for header, payload in super()._read_events():
409
+ try:
410
+ function_id = CallbackID(header.function_id)
411
+ except ValueError:
412
+ # Invalid header. Drop the packet.
413
+ continue
414
+ if function_id in registered_events:
415
+ value = unpack_payload(payload, self.CALLBACK_FORMATS[function_id])
416
+ if function_id is CallbackID.TEMPERATURE:
417
+ yield Event(self, 0, function_id, self.__value_to_si(value))
418
+ else:
419
+ yield Event(self, 1, function_id, value)
@@ -18,6 +18,7 @@ from .bricklet_industrial_dual_analog_in_v2 import BrickletIndustrialDualAnalogI
18
18
  from .bricklet_industrial_ptc import BrickletIndustrialPtc
19
19
  from .bricklet_io4_v2 import BrickletIO4V2
20
20
  from .bricklet_io16 import BrickletIO16
21
+ from .bricklet_isolator import BrickletIsolator
21
22
  from .bricklet_moisture import BrickletMoisture
22
23
  from .bricklet_motion_detector_v2 import BrickletMotionDetectorV2
23
24
  from .bricklet_ptc import BrickletPtc
@@ -27,6 +28,7 @@ from .bricklet_segment_display_4x7 import BrickletSegmentDisplay4x7
27
28
  from .bricklet_segment_display_4x7_v2 import BrickletSegmentDisplay4x7V2
28
29
  from .bricklet_temperature import BrickletTemperature
29
30
  from .bricklet_temperature_v2 import BrickletTemperatureV2
31
+ from .bricklet_thermocouple_v2 import BrickletThermocoupleV2
30
32
 
31
33
  if TYPE_CHECKING:
32
34
  from . import IPConnectionAsync
@@ -55,7 +57,7 @@ class DeviceFactory:
55
57
  try:
56
58
  return self.__available_devices[device_id](uid, ipcon)
57
59
  except KeyError:
58
- raise ValueError(f"No device available for id {device_id}") from None
60
+ raise ValueError(f"No device available for id {device_id!s}") from None
59
61
 
60
62
 
61
63
  device_factory = DeviceFactory()
@@ -70,8 +72,9 @@ device_factory.register(BrickletHumidity)
70
72
  device_factory.register(BrickletHumidityV2)
71
73
  device_factory.register(BrickletIndustrialDualAnalogInV2)
72
74
  device_factory.register(BrickletIndustrialPtc)
73
- device_factory.register(BrickletIO16)
74
75
  device_factory.register(BrickletIO4V2)
76
+ device_factory.register(BrickletIO16)
77
+ device_factory.register(BrickletIsolator)
75
78
  device_factory.register(BrickletMoisture)
76
79
  device_factory.register(BrickletMotionDetectorV2)
77
80
  device_factory.register(BrickletPtc)
@@ -81,3 +84,4 @@ device_factory.register(BrickletSegmentDisplay4x7V2)
81
84
  device_factory.register(BrickletRS232V2)
82
85
  device_factory.register(BrickletTemperature)
83
86
  device_factory.register(BrickletTemperatureV2)
87
+ device_factory.register(BrickletThermocoupleV2)
@@ -56,10 +56,12 @@ class DeviceIdentifier(Enum):
56
56
  BRICKLET_MOTION_DETECTOR_V2 = 292
57
57
  BRICKLET_PTC_V2 = 2101
58
58
  BRICKLET_RS232_V2 = 2108
59
+ BRICKLET_THERMOCOUPLE_V2 = 2109
59
60
  BRICKLET_IO_4_V2 = 2111
60
61
  BRICKLET_TEMPERATURE_V2 = 2113
61
62
  BRICKLET_BAROMETER_V2 = 2117
62
63
  BRICKLET_INDUSTRIAL_DUAL_ANALOG_IN_V2 = 2121
64
+ BRICKLET_ISOLATOR = 2122
63
65
  BRICKLET_AMBIENT_LIGHT_V3 = 2131
64
66
  BRICKLET_SEGMENT_DISPLAY_4x7_V2 = 2137 # pylint: disable=invalid-name
65
67
  BRICKLET_INDUSTRIAL_PTC = 2164
@@ -483,9 +485,19 @@ class BasicCallbackConfiguration(NamedTuple):
483
485
  maximum: Decimal
484
486
 
485
487
 
488
+ class SimpleCallbackConfiguration(NamedTuple):
489
+ period: int
490
+ value_has_to_change: bool
491
+
492
+
486
493
  class AdvancedCallbackConfiguration(NamedTuple):
487
494
  period: int
488
495
  value_has_to_change: bool
489
496
  option: ThresholdOption | None
490
497
  minimum: Decimal | None
491
498
  maximum: Decimal | None
499
+
500
+
501
+ class GetSPITFPBaudrateConfig(NamedTuple):
502
+ enable_dynamic_baudrate: bool
503
+ minimum_dynamic_baudrate: int
@@ -318,7 +318,7 @@ class IPConnectionAsync: # pylint: disable=too-many-instance-attributes
318
318
  try:
319
319
  yield data.enumeration_type, device_factory.get(self, data.device_id, data.uid) # type: ignore
320
320
  except ValueError:
321
- self.__logger.warning("No driver for device id '%i' found.", data.device_id)
321
+ self.__logger.warning("No driver for device id '%s' found.", data.device_id)
322
322
 
323
323
  async def enumerate(self) -> None:
324
324
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
- Name: tinkerforge-async
3
- Version: 1.4.3
2
+ Name: tinkerforge_async
3
+ Version: 1.5.1
4
4
  Summary: Python3 AsyncIO Tinkerforge driver
5
5
  Author-email: Patrick Baus <patrick.baus@physik.tu-darmstadt.de>
6
6
  License: GNU General Public License v3 (GPLv3)
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.8
14
14
  Classifier: Programming Language :: Python :: 3.9
15
15
  Classifier: Programming Language :: Python :: 3.10
16
16
  Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
17
18
  Classifier: Development Status :: 5 - Production/Stable
18
19
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
19
20
  Classifier: Operating System :: OS Independent
@@ -33,6 +34,7 @@ Requires-Dist: isort ; extra == 'dev'
33
34
  Requires-Dist: mypy ; extra == 'dev'
34
35
  Requires-Dist: pre-commit ; extra == 'dev'
35
36
  Requires-Dist: pylint ; extra == 'dev'
37
+ Requires-Dist: setuptools ; extra == 'dev'
36
38
  Requires-Dist: twine ; extra == 'dev'
37
39
  Provides-Extra: doc
38
40
  Requires-Dist: myst-parser ; extra == 'doc'
@@ -41,11 +43,13 @@ Provides-Extra: test
41
43
  Requires-Dist: mypy ; extra == 'test'
42
44
  Requires-Dist: pylint ; extra == 'test'
43
45
  Requires-Dist: pytest ; extra == 'test'
46
+ Requires-Dist: setuptools ; extra == 'test'
44
47
 
45
- [![pylint](https://github.com/PatrickBaus/tinkerforge_async/actions/workflows/pylint.yml/badge.svg)](https://github.com/PatrickBaus/tinkerforge_async/actions/workflows/pylint.yml)
48
+ [![pylint](../../actions/workflows/pylint.yml/badge.svg)](../../actions/workflows/pylint.yml)
46
49
  [![PyPI](https://img.shields.io/pypi/v/tinkerforge-async)](https://pypi.org/project/tinkerforge-async/)
47
50
  ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/tinkerforge-async)
48
51
  ![PyPI - Status](https://img.shields.io/pypi/status/tinkerforge-async)
52
+ [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](LICENSE)
49
53
  [![code style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
50
54
  # TinkerforgeAsync
51
55
  This is a reimplementation of the Tinkerforge Python bindings ([original Python bindings](https://www.tinkerforge.com/en/doc/Software/API_Bindings_Python.html)) using Python 3 asyncio. The original bindings used threads to manage the blocking operations. A much cleaner implementation is possible using the `await` syntax from asyncio.
@@ -59,28 +63,30 @@ The library is fully type-hinted.
59
63
  |--|--|--|--|
60
64
  |[Master](https://www.tinkerforge.com/en/doc/Hardware/Bricks/Master_Brick.html)|:heavy_check_mark:|:heavy_check_mark:| |
61
65
 
62
- |Bricklet|Supported|Tested|
63
- |--|--|--|
64
- |[Ambient Light 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Ambient_Light_V2.html)|:heavy_check_mark:|:heavy_check_mark:|
65
- |[Ambient Light 3.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Ambient_Light_V3.html)|:heavy_check_mark:|:heavy_check_mark:|
66
- |[Analog In](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Analog_In.html)|:heavy_check_mark:|:heavy_check_mark:|
67
- |[Barometer](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Barometer.html)|:heavy_check_mark:|:heavy_check_mark:|
68
- |[Barometer 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Barometer_V2.html)|:heavy_check_mark:|:heavy_check_mark:|
69
- |[Humidity](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Humidity.html)|:heavy_check_mark:|:heavy_check_mark:|
70
- |[Humidity 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Humidity_V2.html)|:heavy_check_mark:|:heavy_check_mark:|
71
- |[Industrial Dual Analog In Bricklet 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Industrial_Dual_Analog_In_V2.html)|:heavy_check_mark:|:heavy_check_mark:|
72
- |[Industrial PTC](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Industrial_PTC.html)|:heavy_check_mark:|:heavy_check_mark:|
73
- |[IO-4 2.0](https://www.tinkerforge.com/de/doc/Hardware/Bricklets/IO4_V2.html)|:heavy_check_mark:|:heavy_check_mark:|
74
- |[IO-16](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/IO16.html)|:heavy_check_mark:|:heavy_check_mark:|
75
- |[Moisture](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Moisture.html)|:heavy_check_mark:|:heavy_check_mark:|
76
- |[Motion Detector 2.0](https://www.tinkerforge.com/de/doc/Hardware/Bricklets/Motion_Detector_V2.html)|:heavy_check_mark:|:heavy_check_mark:|
77
- |[PTC Bricklet](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/PTC.html)|:heavy_check_mark:|:heavy_check_mark:|
78
- |[PTC Bricklet 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/PTC_V2.html)|:heavy_check_mark:|:heavy_check_mark:|
79
- |[RS232 Bricklet 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/RS232_V2.html)|:heavy_check_mark:|:heavy_check_mark:|
80
- |[Segment Display 4x7 Bricklet](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Segment_Display_4x7.html)|:heavy_check_mark:|:heavy_check_mark:|
81
- |[Segment Display 4x7 Bricklet 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Segment_Display_4x7_V2.html)|:heavy_check_mark:|:heavy_check_mark:|
82
- |[Temperature](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Temperature.html)|:heavy_check_mark:|:heavy_check_mark:|
83
- |[Temperature 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Temperature_V2.html)|:heavy_check_mark:|:heavy_check_mark:|
66
+ | Bricklet |Supported|Tested|
67
+ |--------------------------------------------------------------------------------------------------------------------------|--|--|
68
+ | [Ambient Light 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Ambient_Light_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
69
+ | [Ambient Light 3.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Ambient_Light_V3.html) |:heavy_check_mark:|:heavy_check_mark:|
70
+ | [Analog In](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Analog_In.html) |:heavy_check_mark:|:heavy_check_mark:|
71
+ | [Barometer](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Barometer.html) |:heavy_check_mark:|:heavy_check_mark:|
72
+ | [Barometer 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Barometer_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
73
+ | [Humidity](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Humidity.html) |:heavy_check_mark:|:heavy_check_mark:|
74
+ | [Humidity 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Humidity_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
75
+ | [Industrial Dual Analog In 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Industrial_Dual_Analog_In_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
76
+ | [Industrial PTC](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Industrial_PTC.html) |:heavy_check_mark:|:heavy_check_mark:|
77
+ | [IO-4 2.0](https://www.tinkerforge.com/de/doc/Hardware/Bricklets/IO4_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
78
+ | [IO-16](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/IO16.html) |:heavy_check_mark:|:heavy_check_mark:|
79
+ | [Isolator](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Isolator.html) |:heavy_check_mark:|:heavy_check_mark:|
80
+ | [Moisture](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Moisture.html) |:heavy_check_mark:|:heavy_check_mark:|
81
+ | [Motion Detector 2.0](https://www.tinkerforge.com/de/doc/Hardware/Bricklets/Motion_Detector_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
82
+ | [PTC](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/PTC.html) |:heavy_check_mark:|:heavy_check_mark:|
83
+ | [PTC 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/PTC_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
84
+ | [RS232 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/RS232_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
85
+ | [Segment Display 4x7](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Segment_Display_4x7.html) |:heavy_check_mark:|:heavy_check_mark:|
86
+ | [Segment Display 4x7 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Segment_Display_4x7_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
87
+ | [Temperature](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Temperature.html) |:heavy_check_mark:|:heavy_check_mark:|
88
+ | [Temperature 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Temperature_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
89
+ | [Thermocouple 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Thermocouple_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
84
90
 
85
91
  ## Documentation
86
92
  The documentation is currently work in progress. The full documentation will be moved to
@@ -200,6 +206,11 @@ Some design choices of the original Tinkerforge API are overly complex. I theref
200
206
  - `BrickletPtcV2()` takes an additional parameter to define the type of sensor. The options are `BrickletPtc.SensorType.PT_100` and `BrickletPtc.SensorType.PT_1000`. This only determines the resistance returned by the bricklet. The default is `BrickletPtc.SensorType.PT_100`.
201
207
  - `BrickletPtcV2.sensor_type` getter and setter to change the type of sensor used.
202
208
 
209
+ - ### [Thermocouple Bricklet 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Thermocouple_V2.html)
210
+ - `BrickletThermocoupleV2()` takes an additional parameter to define the type of sensor. The options are of type `BrickletThermocoupleV2.SensorType`. The default is `BrickletPtc.SensorType.TYPE_K`.
211
+ - `BrickletThermocoupleV2.sensor_type` getter and setter to change the type of sensor used.
212
+
213
+
203
214
  - ### [Segment Display 4x7 Bricklet 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Segment_Display_4x7_V2.html)
204
215
  - `BrickletSegmentDisplay4x7V2.set_segments()` takes a `list`/`tuple` of 4 `int` instead of digit0, digit1, digit2, digit3. This is the same API as the older [Segment Display 4x7 Bricklet](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Segment_Display_4x7.html).
205
216
 
@@ -213,11 +224,11 @@ python3 setup.py install
213
224
 
214
225
  ## Versioning
215
226
  I use [SemVer](http://semver.org/) for versioning. For the versions available, see the
216
- [tags on this repository](https://github.com/PatrickBaus/tinkerforge_async/tags).
227
+ [tags on this repository](../../tags).
217
228
 
218
229
  ## Authors
219
230
  * **Patrick Baus** - *Initial work* - [PatrickBaus](https://github.com/PatrickBaus)
220
231
 
221
232
  ## License
222
233
  This project is licensed under the GPL v3 license - see the
223
- [LICENSE](https://github.com/PatrickBaus/tinkerforge_async/tree/master/LICENSE) file for details
234
+ [LICENSE](LICENSE) file for details
@@ -1,7 +1,7 @@
1
1
  tinkerforge_async/__init__.py,sha256=wv8UTQrY0vlHwJEO-50PAeUt1cnrAdtSW-2by3CtaaE,376
2
- tinkerforge_async/_version.py,sha256=DaoccQjso9h0diBn3wIUAAm-RSg-GOwYzJMv71m7Zcs,65
2
+ tinkerforge_async/_version.py,sha256=j810yQNq3Z7Fajr2UL0UmEdJ7yojsN6oH_lSF3m9F8g,65
3
3
  tinkerforge_async/async_event_bus.py,sha256=Ng1bNw4tfPZUSMBudy47rTxLqJF96qpTEJIzh1MCq44,1806
4
- tinkerforge_async/brick_master.py,sha256=RIEEZOZZV1qf0cvArxarV2B_DQ30NruRwZDBkP38u6A,129695
4
+ tinkerforge_async/brick_master.py,sha256=kZDN_FzuYmGjaZvYFI2ba2Sfv1mwGoFx9ZayH1DJGqI,129607
5
5
  tinkerforge_async/bricklet_ambient_light_v2.py,sha256=6OVxGK8kBU_ZcRXa9iJH_B8GbZ74XGBB5ix7WquS8yw,13402
6
6
  tinkerforge_async/bricklet_ambient_light_v3.py,sha256=oJ9K9HEI5fX0Tz9YDkfjyiGLsVuguOT5ukhnLsULnto,12171
7
7
  tinkerforge_async/bricklet_analog_in.py,sha256=RwHj6VVg95OBbBt3xKTdxU_mCLI6ByUztPfTTyLPggs,17154
@@ -9,25 +9,27 @@ tinkerforge_async/bricklet_barometer.py,sha256=tSlI4LuuQ_X0-RIqJdeke1XCryzJ7UAGh
9
9
  tinkerforge_async/bricklet_barometer_v2.py,sha256=dO7SP67iASTZZ8pDSBprQTevpMDC8IFHY_MoL6-hfKk,26567
10
10
  tinkerforge_async/bricklet_humidity.py,sha256=_PVk3zUYr4o4o7Eyw2L7dLTS0alR9zrmXNMH2fPe6cE,14948
11
11
  tinkerforge_async/bricklet_humidity_v2.py,sha256=6JwWin22Kr_qtZ9-o7ioGpfk5LQcybHzq1LIahGpOb0,19611
12
- tinkerforge_async/bricklet_industrial_dual_analog_in_v2.py,sha256=xsiMclSw4nLwpW7oJ9MJdy_N34EOrcdNIw28J89PpAA,20352
12
+ tinkerforge_async/bricklet_industrial_dual_analog_in_v2.py,sha256=nmkcYArdBXDO7Q6epGAMgGixlrT5kZIrMzlxddeAWGY,20291
13
13
  tinkerforge_async/bricklet_industrial_ptc.py,sha256=psGwgSArRgU-LgagUQVC8DIznHb1kmXSUNUG-1dfevI,608
14
14
  tinkerforge_async/bricklet_io16.py,sha256=bIraXe_vkJrmSlTV9wbSKDRUY4K1fGc8kCaR0PWaKj0,20875
15
- tinkerforge_async/bricklet_io4_v2.py,sha256=Pja0ANxRJCmXM5zDpBWyS5X7DTHouDn6pEpzrzB0D3c,21591
15
+ tinkerforge_async/bricklet_io4_v2.py,sha256=GYb2N44jVV_hvijJ_YPx2Vf0Td-oJzGNT53gI1mNv2U,21506
16
+ tinkerforge_async/bricklet_isolator.py,sha256=miTYcDMzY6gQ8lNU8ZS6vcPs0HDr8JrJ0y1J7nKsJHs,11159
16
17
  tinkerforge_async/bricklet_moisture.py,sha256=ICnnwPAcWmFcOL73OGWYlLlnAxsr_g7RUe6eZUNDR5I,10078
17
18
  tinkerforge_async/bricklet_motion_detector_v2.py,sha256=nCbYQd4staw62_mYcUVF1qBhzG_04y0jbzXGOyLXcWQ,6451
18
- tinkerforge_async/bricklet_ptc.py,sha256=QU4AwystKH4m0lrOLLHTIWHfUhF0s9HDVEI7me3EGyA,21722
19
- tinkerforge_async/bricklet_ptc_v2.py,sha256=BuKfBh6kzYC-yeP1JCXnT3rtLSXCD8czt02f5a9gjE8,22210
19
+ tinkerforge_async/bricklet_ptc.py,sha256=6tuVQvJVmM3LuRrvFJdDIXiNt-ArLeHQJkIqYuekqRY,22159
20
+ tinkerforge_async/bricklet_ptc_v2.py,sha256=tsH3e_Ppi7XQvhXzQclLxdubw8aZwSnkB0mPHaAsRUo,22648
20
21
  tinkerforge_async/bricklet_rs232_v2.py,sha256=fsZ6SS5ZwJFUrQhXcKatvAki6Vni-ozz58zpri65ZRc,18053
21
22
  tinkerforge_async/bricklet_segment_display_4x7.py,sha256=kl_ctg86w2-uPhEgiraSbtIDS0PH854_9LdA48xrBiQ,6404
22
23
  tinkerforge_async/bricklet_segment_display_4x7_v2.py,sha256=T5g-voFLtLAOyWKn_TNuKDJVaG5vi_7eVCNvkE5ziIs,8902
23
24
  tinkerforge_async/bricklet_temperature.py,sha256=wsaI5vq50d7X_FonRZfxpjtNOVM8tdqA74MPVrts8h4,11341
24
25
  tinkerforge_async/bricklet_temperature_v2.py,sha256=uYSnfW1Hr1WxY5M7kVahtpaQEK5XvdIhM_HhdJdSc-g,9702
25
- tinkerforge_async/device_factory.py,sha256=5mPcQ_EOeV4PL6wj9aa8KG0Bqw7jJCSAw8UBYIKHB7Q,3168
26
- tinkerforge_async/devices.py,sha256=vF-FFqg0hriXfFoTpJVR6IwL7Agsr3hQGbDEU2-H-b0,15361
27
- tinkerforge_async/ip_connection.py,sha256=zzShlFMSL2i7KU4kOCIuWQ3clzT5gi9ajE__qR_ygvQ,27671
26
+ tinkerforge_async/bricklet_thermocouple_v2.py,sha256=b-AqlPsxMqxfxGPNE5oP3Ww0h--nzTWhe-n7Qmp2gp4,15155
27
+ tinkerforge_async/device_factory.py,sha256=UkK8mU-UN3bBPI9Z8kRpbUslxwGbUiGglFnGRyg6c9o,3369
28
+ tinkerforge_async/devices.py,sha256=XQezaYuiH25MX8rD7sVMdfERYhDlvUg8x1jhj3xNsKI,15634
29
+ tinkerforge_async/ip_connection.py,sha256=KPAFGTysuCj8uVWMgVUDvP_zPOpjeYOKVb16SDLRcjE,27671
28
30
  tinkerforge_async/ip_connection_helper.py,sha256=kt4JhONMxJdN4upIpVZlqTKmQcSyG2zXkmnCC2QL91Y,4305
29
- tinkerforge_async-1.4.3.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
30
- tinkerforge_async-1.4.3.dist-info/METADATA,sha256=qsraKkhKYeH1PGB1uLORkUkmKBkhUEBwiM9VmqQVu5c,15068
31
- tinkerforge_async-1.4.3.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
32
- tinkerforge_async-1.4.3.dist-info/top_level.txt,sha256=YuYlWDVtbFvjqm-GoyH2asasmmn-lH1KeKBBtA17QJ4,18
33
- tinkerforge_async-1.4.3.dist-info/RECORD,,
31
+ tinkerforge_async-1.5.1.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
32
+ tinkerforge_async-1.5.1.dist-info/METADATA,sha256=bolO8k2cFe00_kmgDqRgvQ247vVl53F6PzRV2quCD6I,16699
33
+ tinkerforge_async-1.5.1.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
34
+ tinkerforge_async-1.5.1.dist-info/top_level.txt,sha256=YuYlWDVtbFvjqm-GoyH2asasmmn-lH1KeKBBtA17QJ4,18
35
+ tinkerforge_async-1.5.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.2)
2
+ Generator: setuptools (70.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5