Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add thermocouple bricklet #5

Merged
merged 6 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The library is fully type-hinted.
| [Segment Display 4x7 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Segment_Display_4x7_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
| [Temperature](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Temperature.html) |:heavy_check_mark:|:heavy_check_mark:|
| [Temperature 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Temperature_V2.html) |:heavy_check_mark:|:heavy_check_mark:|
| [Thermocouple 2.0](https://www.tinkerforge.com/en/doc/Hardware/Bricklets/Thermocouple_V2.html) |:heavy_check_mark:|:heavy_check_mark:|

## Documentation
The documentation is currently work in progress. The full documentation will be moved to
Expand Down
120 changes: 120 additions & 0 deletions examples/bricklet_thermocouple_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env python3
# pylint: disable=duplicate-code
"""
An example to demonstrate most of the capabilities of the Tinkerforge Thermocouple Bricklet 2.0.
"""
import asyncio
import warnings
from decimal import Decimal

from tinkerforge_async.bricklet_thermocouple_v2 import BrickletThermocoupleV2
from tinkerforge_async.devices import BrickletWithMCU
from tinkerforge_async.ip_connection import IPConnectionAsync


async def process_callbacks(device: BrickletThermocoupleV2) -> None:
"""Prints the callbacks (filtered by id) of the bricklet."""
async for packet in device.read_events():
print("Callback received", packet)


async def run_example_generic(bricklet: BrickletWithMCU) -> None:
"""This is a demo of the generic features of the Tinkerforge bricklets with a microcontroller."""
uid = await bricklet.read_uid()
print("Device uid:", uid)
await bricklet.write_uid(uid)

print("SPI error count:", await bricklet.get_spitfp_error_count())

print("Current bootloader mode:", await bricklet.get_bootloader_mode())
bootloader_mode = bricklet.BootloaderMode.FIRMWARE
print("Setting bootloader mode to", bootloader_mode, ":", await bricklet.set_bootloader_mode(bootloader_mode))

print("Disable status LED")
await bricklet.set_status_led_config(bricklet.LedConfig.OFF)
print("Current status:", await bricklet.get_status_led_config())
await asyncio.sleep(1)
print("Enable status LED")
await bricklet.set_status_led_config(bricklet.LedConfig.SHOW_STATUS)
print("Current status:", await bricklet.get_status_led_config())

print("Get Chip temperature:", await bricklet.get_chip_temperature() - Decimal("273.15"), "°C")

print("Reset Bricklet")
await bricklet.reset()


async def run_example(bricklet: BrickletThermocoupleV2) -> None:
"""This is the actual demo. If the bricklet is found, this code will be run."""
callback_task = asyncio.create_task(process_callbacks(bricklet))
try:
print("Identity:", await bricklet.get_identity())

# Query the value
print("Get temperature:", await bricklet.get_temperature())
print("Set callback period to", 1000, "ms")
print("Set threshold to >10 °C and wait for callbacks")
# We use a low temperature value on purpose, so that the callback will be triggered
await bricklet.set_temperature_callback_configuration(
period=1000, value_has_to_change=False, option=bricklet.ThresholdOption.GREATER_THAN, minimum=10, maximum=0
)
print("Temperature callback configuration:", await bricklet.get_temperature_callback_configuration())
await asyncio.sleep(10.1) # Wait for 2-3 callbacks
print("Disable threshold callback")
await bricklet.set_temperature_callback_configuration()
print("Temperature callback configuration:", await bricklet.get_temperature_callback_configuration())

over_under, opencircuit = await bricklet.get_error_state()
print(f"Reading errors. Over-/Undervoltage: {over_under}, Open circuit: {opencircuit}")

# Test the generic features of the bricklet. These are available with all
# new bricklets that have a microcontroller
await run_example_generic(bricklet)
finally:
callback_task.cancel()


async def shutdown(tasks: set[asyncio.Task]) -> None:
"""Clean up by stopping all consumers"""
for task in tasks:
task.cancel()
await asyncio.gather(*tasks)


async def main() -> None:
"""
The main loop, that will spawn all callback handlers and wait until they are done. There are two callback handlers,
one waits for the bricklet to connect and runs the demo, the other handles messages sent by the bricklet.
"""
tasks = set()
try:
# Use the context manager of the ip connection. It will automatically do the cleanup.
async with IPConnectionAsync(host="127.0.0.1", port=4223) as connection:
await connection.enumerate()
# Read all enumeration replies, then start the example if we find the correct device
async for enumeration_type, device in connection.read_enumeration(): # pylint: disable=unused-variable
if isinstance(device, BrickletThermocoupleV2):
print(f"Found {device}, running example.")
tasks.add(asyncio.create_task(run_example(device)))
break
print(f"Found {device}, but not interested.")

# Wait for run_example() to finish
await asyncio.gather(*tasks)
except ConnectionRefusedError:
print("Could not connect to server. Connection refused. Is the brick daemon up?")
except asyncio.CancelledError:
print("Stopped the main loop.")
raise # It is good practice to re-raise CancelledErrors
finally:
await shutdown(tasks)


# Report all mistakes managing asynchronous resources.
warnings.simplefilter("always", ResourceWarning)

# Start the main loop and run the async loop forever. Turn off the debug parameter for production code.
try:
asyncio.run(main(), debug=True)
except KeyboardInterrupt:
print("Shutting down gracefully.")
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: OS Independent",
Expand Down Expand Up @@ -44,7 +45,7 @@ doc = [
]

test = [
"mypy", "pylint", "pytest",
"mypy", "pylint", "pytest", "setuptools"
]

[tool.pylint.'MESSAGES CONTROL']
Expand Down
14 changes: 11 additions & 3 deletions tinkerforge_async/bricklet_ptc.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class CallbackID(Enum):
SENSOR_CONNECTED = 24


# We need the alias for MyPy type hinting
# See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
_CallbackID = CallbackID


Expand Down Expand Up @@ -73,13 +75,15 @@ class LineFilter(Enum):
FREQUENCY_60HZ = 1


_LineFilter = LineFilter # We need the alias for MyPy type hinting
# We need the alias for MyPy type hinting
# See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
_LineFilter = LineFilter


@unique
class WireMode(Enum):
"""
Select the measurement setup. Use 3 or wires to eliminate most/all of the
Select the measurement setup. Use 3 or 4 wires to eliminate most/all the
resistance of the wire. Use 3 or 4 wire setups when using PT100 and long
cables.
"""
Expand All @@ -89,7 +93,9 @@ class WireMode(Enum):
WIRE_4 = 4


_WireMode = WireMode # We need the alias for MyPy type hinting
# We need the alias for MyPy type hinting
# See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
_WireMode = WireMode


@unique
Expand All @@ -102,6 +108,8 @@ class SensorType(Enum):
PT_1000 = 1


# We need the alias for MyPy type hinting
# See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
_SensorType = SensorType


Expand Down
12 changes: 10 additions & 2 deletions tinkerforge_async/bricklet_ptc_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class CallbackID(Enum):
SENSOR_CONNECTED = 18


# We need the alias for MyPy type hinting
# See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
_CallbackID = CallbackID


Expand Down Expand Up @@ -67,7 +69,9 @@ class LineFilter(Enum):
FREQUENCY_60HZ = 1


_LineFilter = LineFilter # We need the alias for MyPy type hinting
# We need the alias for MyPy type hinting
# See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
_LineFilter = LineFilter


@unique
Expand All @@ -82,6 +86,8 @@ class WireMode(Enum):
WIRE_4 = 4


# We need the alias for MyPy type hinting
# See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
_WireMode = WireMode # We need the alias for MyPy type hinting


Expand All @@ -95,7 +101,9 @@ class SensorType(Enum):
PT_1000 = 1


_SensorType = SensorType # We need the alias for MyPy type hinting
# We need the alias for MyPy type hinting
# See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
_SensorType = SensorType


class GetMovingAverageConfiguration(NamedTuple):
Expand Down
Loading