MikrofonSensor und TemperaturSenor die zwei Python programme funktionieren. mit den jeweiligen 2 json Datein. Beim TemperaturSensor wird im Terminal keine Wertre ausgegeben aber in der json Datei kann man die Temp und Hum sehen.

This commit is contained in:
Chiara 2025-05-28 14:53:44 +02:00
parent 4c654ec969
commit 1751076592
2614 changed files with 349009 additions and 0 deletions

View file

@ -0,0 +1,139 @@
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""BCM283x NeoPixel Driver Class"""
import time
import atexit
import _rpi_ws281x as ws
try:
# Used only for typing
from typing import Optional
from digitalio import DigitalInOut
except ImportError:
pass
# LED configuration.
# pylint: disable=redefined-outer-name,too-many-branches,too-many-statements
# pylint: disable=global-statement,protected-access
LED_FREQ_HZ = 800000 # Frequency of the LED signal. We only support 800KHz
LED_DMA_NUM = 10 # DMA channel to use, can be 0-14.
LED_BRIGHTNESS = 255 # We manage the brightness in the neopixel library
LED_INVERT = 0 # We don't support inverted logic
LED_STRIP = None # We manage the color order within the neopixel library
# a 'static' object that we will use to manage our PWM DMA channel
# we only support one LED strip per raspi
_led_strip = None
_buf: Optional[bytearray] = None
def neopixel_write(gpio: DigitalInOut, buf: bytearray) -> None:
"""NeoPixel Writing Function"""
global _led_strip # we'll have one strip we init if its not at first
global _buf # we save a reference to the buf, and if it changes we will cleanup and re-init.
if _led_strip is None or buf is not _buf:
# This is safe to call since it doesn't do anything if _led_strip is None
neopixel_cleanup()
# Create a ws2811_t structure from the LED configuration.
# Note that this structure will be created on the heap so you
# need to be careful that you delete its memory by calling
# delete_ws2811_t when it's not needed.
_led_strip = ws.new_ws2811_t()
_buf = buf
# Initialize all channels to off
for channum in range(2):
channel = ws.ws2811_channel_get(_led_strip, channum)
ws.ws2811_channel_t_count_set(channel, 0)
ws.ws2811_channel_t_gpionum_set(channel, 0)
ws.ws2811_channel_t_invert_set(channel, 0)
ws.ws2811_channel_t_brightness_set(channel, 0)
channel = ws.ws2811_channel_get(_led_strip, _neopixel_detect_channel(gpio))
# Initialize the channel in use
count = 0
if len(buf) % 3 == 0:
# most common, divisible by 3 is likely RGB
LED_STRIP = ws.WS2811_STRIP_RGB
count = len(buf) // 3
elif len(buf) % 4 == 0:
LED_STRIP = ws.SK6812_STRIP_RGBW
count = len(buf) // 4
else:
raise RuntimeError("We only support 3 or 4 bytes-per-pixel")
ws.ws2811_channel_t_count_set(
channel, count
) # we manage 4 vs 3 bytes in the library
ws.ws2811_channel_t_gpionum_set(channel, gpio._pin.id)
ws.ws2811_channel_t_invert_set(channel, LED_INVERT)
ws.ws2811_channel_t_brightness_set(channel, LED_BRIGHTNESS)
ws.ws2811_channel_t_strip_type_set(channel, LED_STRIP)
# Initialize the controller
ws.ws2811_t_freq_set(_led_strip, LED_FREQ_HZ)
ws.ws2811_t_dmanum_set(_led_strip, LED_DMA_NUM)
resp = ws.ws2811_init(_led_strip)
if resp != ws.WS2811_SUCCESS:
if resp == -5:
raise RuntimeError(
"NeoPixel support requires running with sudo, please try again!"
)
message = ws.ws2811_get_return_t_str(resp)
raise RuntimeError(
"ws2811_init failed with code {0} ({1})".format(resp, message)
)
atexit.register(neopixel_cleanup)
channel = ws.ws2811_channel_get(_led_strip, _neopixel_detect_channel(gpio))
if gpio._pin.id != ws.ws2811_channel_t_gpionum_get(channel):
raise RuntimeError("Raspberry Pi neopixel support is for one strip only!")
if ws.ws2811_channel_t_strip_type_get(channel) == ws.WS2811_STRIP_RGB:
bpp = 3
else:
bpp = 4
# assign all colors!
for i in range(len(buf) // bpp):
r = buf[bpp * i]
g = buf[bpp * i + 1]
b = buf[bpp * i + 2]
if bpp == 3:
pixel = (r << 16) | (g << 8) | b
else:
w = buf[bpp * i + 3]
pixel = (w << 24) | (r << 16) | (g << 8) | b
ws.ws2811_led_set(channel, i, pixel)
resp = ws.ws2811_render(_led_strip)
if resp != ws.WS2811_SUCCESS:
message = ws.ws2811_get_return_t_str(resp)
raise RuntimeError(
"ws2811_render failed with code {0} ({1})".format(resp, message)
)
time.sleep(0.001 * ((len(buf) // 100) + 1)) # about 1ms per 100 bytes
def neopixel_cleanup():
"""Cleanup when we're done"""
global _led_strip
if _led_strip is not None:
# Ensure ws2811_fini is called before the program quits.
ws.ws2811_fini(_led_strip)
# Example of calling delete function to clean up structure memory. Isn't
# strictly necessary at the end of the program execution here, but is good practice.
ws.delete_ws2811_t(_led_strip)
_led_strip = None
def _neopixel_detect_channel(gpio: DigitalInOut) -> int:
"""Detect the channel for a given GPIO, added for support PWM1 pins"""
if gpio._pin.id in (13, 19, 41, 45):
return 1
return 0

View file

@ -0,0 +1,96 @@
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""Broadcom BCM283x pin names"""
# Use RPi.GPIO pins for Raspberry Pi 1-3B+
from adafruit_blinka.microcontroller.generic_linux.rpi_gpio_pin import Pin
D0 = Pin(0)
D1 = Pin(1)
D2 = Pin(2)
SDA = Pin(2)
D3 = Pin(3)
SCL = Pin(3)
D4 = Pin(4)
D5 = Pin(5)
D6 = Pin(6)
D7 = Pin(7)
CE1 = Pin(7)
D8 = Pin(8)
CE0 = Pin(8)
D9 = Pin(9)
MISO = Pin(9)
D10 = Pin(10)
MOSI = Pin(10)
D11 = Pin(11)
SCLK = Pin(11) # Raspberry Pi naming
SCK = Pin(11) # CircuitPython naming
D12 = Pin(12)
D13 = Pin(13)
D14 = Pin(14)
TXD = Pin(14)
D15 = Pin(15)
RXD = Pin(15)
D16 = Pin(16)
D17 = Pin(17)
D18 = Pin(18)
D19 = Pin(19)
MISO_1 = Pin(19)
D20 = Pin(20)
MOSI_1 = Pin(20)
D21 = Pin(21)
SCLK_1 = Pin(21)
SCK_1 = Pin(21)
D22 = Pin(22)
D23 = Pin(23)
D24 = Pin(24)
D25 = Pin(25)
D26 = Pin(26)
D27 = Pin(27)
D28 = Pin(28)
D29 = Pin(29)
D30 = Pin(30)
D31 = Pin(31)
D32 = Pin(32)
D33 = Pin(33)
D34 = Pin(34)
D35 = Pin(35)
D36 = Pin(36)
D37 = Pin(37)
D38 = Pin(38)
D39 = Pin(39)
D40 = Pin(40)
MISO_2 = Pin(40)
D41 = Pin(41)
MOSI_2 = Pin(41)
D42 = Pin(42)
SCLK_2 = Pin(42)
SCK_2 = Pin(43)
D43 = Pin(43)
D44 = Pin(44)
D45 = Pin(45)
# ordered as spiId, sckId, mosiId, misoId
spiPorts = (
(0, SCLK, MOSI, MISO),
(1, SCLK_1, MOSI_1, MISO_1),
(2, SCLK_2, MOSI_2, MISO_2),
)
# ordered as uartId, txId, rxId
uartPorts = ((1, TXD, RXD),)
# These are the known hardware I2C ports / pins.
# For software I2C ports created with the i2c-gpio overlay, see:
# https://github.com/adafruit/Adafruit_Python_Extended_Bus
i2cPorts = (
(1, SCL, SDA),
(0, D1, D0), # both pi 1 and pi 2 i2c ports!
)

View file

@ -0,0 +1,187 @@
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""Custom PulseIn Class to read PWM signals"""
import time
import subprocess
import os
import atexit
import random
import struct
import sysv_ipc
DEBUG = False
queues = []
procs = []
# The message queues live outside of python space, and must be formally cleaned!
def final():
"""In case the program is cancelled or quit, we need to clean up the PulseIn
helper process and also the message queue, this is called at exit to do so"""
if DEBUG:
print("Cleaning up message queues", queues)
print("Cleaning up processes", procs)
for q in queues:
q.remove()
for proc in procs:
proc.terminate()
atexit.register(final)
# pylint: disable=c-extension-no-member
class PulseIn:
"""PulseIn Class to read PWM signals"""
def __init__(self, pin, maxlen=2, idle_state=False):
"""Create a PulseIn object associated with the given pin.
The object acts as a read-only sequence of pulse lengths with
a given max length. When it is active, new pulse lengths are
added to the end of the list. When there is no more room
(len() == maxlen) the oldest pulse length is removed to make room."""
self._pin = pin
self._maxlen = maxlen
self._idle_state = idle_state
self._queue_key = random.randint(1, 9999)
try:
self._mq = sysv_ipc.MessageQueue(None, flags=sysv_ipc.IPC_CREX)
if DEBUG:
print("Message Queue Key: ", self._mq.key)
queues.append(self._mq)
except sysv_ipc.ExistentialError:
raise RuntimeError(
"Message queue creation failed"
) from sysv_ipc.ExistentialError
# Check if OS is 64-bit
if struct.calcsize("P") * 8 == 64: # pylint: disable=no-member
libgpiod_filename = "libgpiod_pulsein64"
else:
libgpiod_filename = "libgpiod_pulsein"
dir_path = os.path.dirname(os.path.realpath(__file__))
cmd = [
dir_path + "/" + libgpiod_filename,
"--pulses",
str(maxlen),
"--queue",
str(self._mq.key),
]
if idle_state:
cmd.append("-i")
if isinstance(pin.id, tuple):
cmd.append(f"gpiochip{pin.id[0]}")
cmd.append(str(pin.id[1]))
else:
cmd.append("gpiochip0")
cmd.append(str(pin))
if DEBUG:
print(cmd)
self._process = subprocess.Popen(cmd) # pylint: disable=consider-using-with
procs.append(self._process)
# wait for it to start up
if DEBUG:
print("Waiting for startup success message from subprocess")
message = self._wait_receive_msg(timeout=0.25)
if message[0] != b"!":
raise RuntimeError("Could not establish message queue with subprocess")
self._paused = False
# pylint: disable=redefined-builtin
def _wait_receive_msg(self, timeout=0, type=2):
"""Internal helper that will wait for new messages of a given type,
and throw an exception on timeout"""
if timeout > 0:
stamp = time.monotonic()
while (time.monotonic() - stamp) < timeout:
try:
message = self._mq.receive(block=False, type=type)
return message
except sysv_ipc.BusyError:
time.sleep(0.001) # wait a bit then retry!
# uh-oh timed out
raise RuntimeError(
"Timed out waiting for PulseIn message. Make sure libgpiod is installed."
)
message = self._mq.receive(block=True, type=type)
return message
# pylint: enable=redefined-builtin
def deinit(self):
"""Deinitialises the PulseIn and releases any hardware and software
resources for reuse."""
# Clean up after ourselves
self._process.terminate()
procs.remove(self._process)
self._mq.remove()
queues.remove(self._mq)
def __enter__(self):
"""No-op used by Context Managers."""
return self
def __exit__(self, exc_type, exc_value, tb):
"""Automatically deinitializes the hardware when exiting a context."""
self.deinit()
def resume(self, trigger_duration=0):
"""Resumes pulse capture after an optional trigger pulse."""
if trigger_duration != 0:
self._mq.send("t%d" % trigger_duration, True, type=1)
else:
self._mq.send("r", True, type=1)
self._paused = False
def pause(self):
"""Pause pulse capture"""
self._mq.send("p", True, type=1)
self._paused = True
@property
def paused(self):
"""True when pulse capture is paused as a result of pause() or
an error during capture such as a signal that is too fast."""
return self._paused
@property
def maxlen(self):
"""The maximum length of the PulseIn. When len() is equal to maxlen,
it is unclear which pulses are active and which are idle."""
return self._maxlen
def clear(self):
"""Clears all captured pulses"""
self._mq.send("c", True, type=1)
def popleft(self):
"""Removes and returns the oldest read pulse."""
self._mq.send("^", True, type=1)
message = self._wait_receive_msg()
reply = int(message[0].decode("utf-8"))
# print(reply)
if reply == -1:
raise IndexError("pop from empty list")
return reply
def __len__(self):
"""Returns the current pulse length"""
self._mq.send("l", True, type=1)
message = self._wait_receive_msg()
return int(message[0].decode("utf-8"))
# pylint: disable=redefined-builtin
def __getitem__(self, index, type=None):
"""Returns the value at the given index or values in slice."""
self._mq.send("i%d" % index, True, type=1)
message = self._wait_receive_msg()
ret = int(message[0].decode("utf-8"))
if ret == -1:
raise IndexError("list index out of range")
return ret
# pylint: enable=redefined-builtin

View file

@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT

View file

@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT

View file

@ -0,0 +1,192 @@
# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT
# SPDX-License-Identifier: BSD-3-Clause
"""
`rotaryio` - Support for reading rotation sensors
===========================================================
See `CircuitPython:rotaryio` in CircuitPython for more details.
Raspberry Pi PIO implementation
* Author(s): Melissa LeBlanc-Williams
"""
from __future__ import annotations
import array
import microcontroller
try:
import adafruit_pioasm
from adafruit_rp1pio import StateMachine
except ImportError as exc:
raise ImportError(
"adafruit_pioasm and adafruit_rp1pio are required for this module"
) from exc
_n_read = 17
_program = adafruit_pioasm.Program(
"""
;
; Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;
.pio_version 0 // only requires PIO version 0
.program quadrature_encoder
; the code must be loaded at address 0, because it uses computed jumps
.origin 0
; the code works by running a loop that continuously shifts the 2 phase pins into
; ISR and looks at the lower 4 bits to do a computed jump to an instruction that
; does the proper "do nothing" | "increment" | "decrement" action for that pin
; state change (or no change)
; ISR holds the last state of the 2 pins during most of the code. The Y register
; keeps the current encoder count and is incremented / decremented according to
; the steps sampled
; the program keeps trying to write the current count to the RX FIFO without
; blocking. To read the current count, the user code must drain the FIFO first
; and wait for a fresh sample (takes ~4 SM cycles on average). The worst case
; sampling loop takes 10 cycles, so this program is able to read step rates up
; to sysclk / 10 (e.g., sysclk 125MHz, max step rate = 12.5 Msteps/sec)
; 00 state
jmp update ; read 00
jmp decrement ; read 01
jmp increment ; read 10
jmp update ; read 11
; 01 state
jmp increment ; read 00
jmp update ; read 01
jmp update ; read 10
jmp decrement ; read 11
; 10 state
jmp decrement ; read 00
jmp update ; read 01
jmp update ; read 10
jmp increment ; read 11
; to reduce code size, the last 2 states are implemented in place and become the
; target for the other jumps
; 11 state
jmp update ; read 00
jmp increment ; read 01
decrement:
; note: the target of this instruction must be the next address, so that
; the effect of the instruction does not depend on the value of Y. The
; same is true for the "jmp y--" below. Basically "jmp y--, <next addr>"
; is just a pure "decrement y" instruction, with no other side effects
jmp y--, update ; read 10
; this is where the main loop starts
.wrap_target
update:
mov isr, y ; read 11
push noblock
sample_pins:
; we shift into ISR the last state of the 2 input pins (now in OSR) and
; the new state of the 2 pins, thus producing the 4 bit target for the
; computed jump into the correct action for this state. Both the PUSH
; above and the OUT below zero out the other bits in ISR
out isr, 2
in pins, 2
; save the state in the OSR, so that we can use ISR for other purposes
mov osr, isr
; jump to the correct state machine action
mov pc, isr
; the PIO does not have a increment instruction, so to do that we do a
; negate, decrement, negate sequence
increment:
mov y, ~y
jmp y--, increment_cont
increment_cont:
mov y, ~y
.wrap ; the .wrap here avoids one jump instruction and saves a cycle too
"""
)
_zero_y = adafruit_pioasm.assemble("set y 0")
class IncrementalEncoder:
"""
IncrementalEncoder determines the relative rotational position based on two series of
pulses. It assumes that the encoders common pin(s) are connected to ground,and enables
pull-ups on pin_a and pin_b.
Create an IncrementalEncoder object associated with the given pins. It tracks the
positional state of an incremental rotary encoder (also known as a quadrature encoder.)
Position is relative to the position when the object is constructed.
"""
def __init__(
self, pin_a: microcontroller.Pin, pin_b: microcontroller.Pin, divisor: int = 4
):
"""Create an incremental encoder on pin_a and the next higher pin
Always operates in "x4" mode (one count per quadrature edge)
Assumes but does not check that pin_b is one above pin_a."""
if pin_b is not None and pin_b.id != pin_a.id + 1:
raise ValueError("pin_b must be None or one higher than pin_a")
try:
self._sm = StateMachine(
_program.assembled,
frequency=0,
init=_zero_y,
first_in_pin=pin_a,
in_pin_count=2,
pull_in_pin_up=0x3,
auto_push=True,
push_threshold=32,
in_shift_right=False,
**_program.pio_kwargs,
)
except RuntimeError as e:
if "(error -13)" in e.args[0]:
raise RuntimeError(
"This feature requires a rules file to allow access to PIO. See "
"https://learn.adafruit.com/circuitpython-on-raspberrypi-linux/"
"using-neopixels-on-the-pi-5#updating-permissions-3189429"
) from e
raise
self._buffer = array.array("i", [0] * _n_read)
self.divisor = divisor
self._position = 0
def deinit(self):
"""Deinitializes the IncrementalEncoder and releases any hardware resources for reuse."""
self._sm.deinit()
def __enter__(self) -> IncrementalEncoder:
"""No-op used by Context Managers."""
return self
def __exit__(self, _type, _value, _traceback):
"""
Automatically deinitializes when exiting a context. See
:ref:`lifetime-and-contextmanagers` for more info.
"""
self.deinit()
@property
def position(self):
"""The current position in terms of pulses. The number of pulses per rotation is defined
by the specific hardware and by the divisor."""
self._sm.readinto(self._buffer) # read N stale values + 1 fresh value
raw_position = self._buffer[-1]
delta = int((raw_position - self._position * self.divisor) / self.divisor)
self._position += delta
return self._position