Python – Pollux Labs https://polluxlabs.net Arduino, ESP32 & ESP8266 | Projekte & Tutorials Sun, 17 Nov 2024 12:18:35 +0000 de hourly 1 https://wordpress.org/?v=6.6.2 https://polluxlabs.net/wp-content/uploads/2020/05/cropped-pollux-labs-p-32x32.png Python – Pollux Labs https://polluxlabs.net 32 32 Geheime Botschaften: Verschlüsselte Nachrichten als Audio übertragen https://polluxlabs.net/python-tutorials-und-projekte/geheime-botschaften-verschluesselte-nachrichten-als-audio-uebertragen/ Sun, 17 Nov 2024 12:18:33 +0000 https://polluxlabs.net/?p=17906 Geheime Botschaften: Verschlüsselte Nachrichten als Audio übertragen Weiterlesen »

]]>
Nachrichten zu versenden, die Ende-zu-Ende-verschlüsselt sind, gehört mittlerweile zum Standard vieler Nachrichten-Apps wie Signal, Threema und WhatsApp. Aber wie wäre es mit etwas spielerischem Retro-Charme? In diesem Projekt wandelst du Textnachrichten in Töne um und versendest sie als Audio-Dateien im Anhang einer E-Mail. Der Empfänger kann diese Audio-Dateien dann mit Hilfe eines zuvor zwischen euch vereinbarten Schlüsselworts entschlüsseln und lesen. Nicht Eingeweihte hören nur eine Abfolge von Tönen, wie in diesem Beispiel:

Zum Einsatz kommen hierbei zwei Python-Scripte – je eines für den Sender und den Empfänger. Als E-Mail-Provider dient Gmail.

Gmail für den Versand der E-Mails einrichten

Zunächst benötigst du einen E-Mail-Provider, den du aus dem Python-Script des Senders ansteuern und für den Versand der E-Mails nutzen kannst. Hier bietet sich Googles Gmail an, da die Einrichtung unkompliziert ist. Wichtig: Falls du bereits eine Mail-Adresse bei Gmail besitzt, richte dir für dieses Projekt trotzdem eine neue ein. So stellst du sicher, dass zum Beispiel ein fehlerhaftes Versenden von vielen E-Mails hintereinander zu einer vorübergehenden Sperrung deines Kontos führt.

Wie du eine E-Mail-Adresse bei Gmail und sie für den Versand aus einem Python-Script einrichtest, erfährst du in diesem Tutorial.

Die benötigten Python-Bibliotheken

Im Folgenden verwendest du die Bibliotheken numpy und scipy. Die numpy-Bibliothek wird später verwendet, um numerische Operationen durchzuführen, die für die Analyse der Frequenzen in den Audiodaten benötigt werden. Die scipy-Bibliothek enthält die Funktion wavfile.read, die verwendet wird, um die erzeugten WAV-Datei einzulesen und die Audiodaten sowie die Abtastrate zu extrahieren. Diese Bibliotheken sind nicht standardmäßig in Python enthalten und müssen daher manuell installiert werden. Um sie zu installieren, verwenden Sie den folgenden Befehl:

pip install numpy scipy

Das Script für den Sender der verschlüsselten Nachrichten

Wenn du nun eine E-Mail-Adresse bei Gmail eingerichtet und die beiden benötigten Bibliotheken installiert hast, kann es direkt weitergehen mit dem Python-Script für den Sender. Hier der vollständige Code:

___STEADY_PAYWALL___

# Verschlüsselte Nachrichten - Script für den Sender
# Pollux Labs, polluxlabs.net

import numpy as np
from scipy.io.wavfile import write
import smtplib
from email.message import EmailMessage
import socket

# Parameter, die vom Benutzer bearbeitet werden müssen
user_parameters = {
    "sample_rate": 44100,  # Abtastrate (Hz)
    "bit_duration": 0.1,   # Dauer eines Bits (in Sekunden)
    "freq_0": 1000,        # Frequenz für "0" (Hz)
    "freq_1": 2000,        # Frequenz für "1" (Hz)
    "encryption_key": "geheimer_schluessel",  # Verschlüsselungsschlüssel (beide Parteien müssen denselben Schlüssel verwenden)
    "sender_email": "Absender-Adresse",  # Absender-E-Mail-Adresse
    "sender_password": "App-Passwort",        # App-Passwort für die Absender-E-Mail
    "receiver_email": "Empfänger-Adresse",      # Empfänger-E-Mail-Adresse
    "email_subject": "Betreff",   # Betreff der E-Mail
    "email_body": "Inhalt der E-Mail, z.B. Hier kommt eine verschlüsselte Nachricht für dich.",  # E-Mail-Inhalt
    "wav_filename": "message.wav"           # Name der zu speichernden WAV-Datei
}

# Funktion zur Erstellung eines Tons für ein Bit
def generate_tone(frequency, duration, sample_rate):
    # Erzeugt eine Zeitachse von 0 bis zur angegebenen Dauer mit der entsprechenden Anzahl an Samples
    t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
    # Berechnet den Sinuswert für die gegebene Frequenz über die Zeitachse
    return np.sin(2 * np.pi * frequency * t)

# Nachricht in Binärdaten umwandeln
def text_to_binary(text):
    # Wandelt jeden Buchstaben der Nachricht in eine 8-Bit Binärdarstellung um
    binary_data = ''.join(format(ord(char), '08b') for char in text)
    return binary_data

# Nachricht mit dem Schlüssel verschlüsseln
def encrypt_message(text, key):
    encrypted_message = ""
    for i in range(len(text)):
        encrypted_char = chr(ord(text[i]) ^ ord(key[i % len(key)]))
        encrypted_message += encrypted_char
    return encrypted_message

# Nachricht in modulierte Audiodaten umwandeln
def encode_to_audio(binary_data, bit_duration, sample_rate, freq_0, freq_1):
    # Initialisiert ein leeres Array für die Audiodaten
    audio = np.array([])
    # Iteriert durch jedes Bit der Binärdaten
    for bit in binary_data:
        # Erzeugt einen Ton für "0" oder "1" und fügt ihn an das Audioarray an
        if bit == '0':
            audio = np.append(audio, generate_tone(freq_0, bit_duration, sample_rate))
        else:
            audio = np.append(audio, generate_tone(freq_1, bit_duration, sample_rate))
    return audio

# Funktion zum Versenden der WAV-Datei per E-Mail
def send_email_with_attachment(receiver_email, subject, body, attachment_path):
    # Absender-E-Mail und Passwort
    sender_email = user_parameters["sender_email"]
    sender_password = user_parameters["sender_password"]

    # Erstellen der E-Mail-Nachricht
    msg = EmailMessage()
    msg['From'] = sender_email
    msg['To'] = receiver_email
    msg['Subject'] = subject
    msg.set_content(body)

    # Anhang hinzufügen (die WAV-Datei)
    with open(attachment_path, 'rb') as attachment:
        msg.add_attachment(attachment.read(), maintype='audio', subtype='wav', filename=attachment_path)

    try:
        # SMTP-Server einrichten und die E-Mail senden
        with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
            smtp.login(sender_email, sender_password)  # Anmelden am SMTP-Server
            smtp.send_message(msg)  # E-Mail senden
    except socket.gaierror:
        print("Fehler: Der SMTP-Server konnte nicht erreicht werden. Bitte überprüfen Sie die Serveradresse.")
    except smtplib.SMTPAuthenticationError:
        print("Fehler: Authentifizierung fehlgeschlagen. Bitte überprüfen Sie Ihre E-Mail-Adresse und Ihr Passwort.")
    except Exception as e:
        print(f"Ein unerwarteter Fehler ist aufgetreten: {e}")

# Hauptprogramm
if __name__ == "__main__":
    # Nachricht erstellen
    email_message = "Das Pferd frisst keinen Gurkensalat."
    
    # Nachricht verschlüsseln
    encrypted_message = encrypt_message(email_message, user_parameters["encryption_key"])
    
    # Verschlüsselte Nachricht in Binärdaten umwandeln
    binary_data = text_to_binary(encrypted_message)
    print(f"Binärdaten der Nachricht: {binary_data[:64]}...")  # Zeigt die ersten 64 Bits der Nachricht (für Debugging)
    
    # Binärdaten in Audiosignale umwandeln
    audio_data = encode_to_audio(binary_data, user_parameters["bit_duration"], user_parameters["sample_rate"], user_parameters["freq_0"], user_parameters["freq_1"])
    
    # WAV-Datei speichern
    wav_filename = user_parameters["wav_filename"]
    # Speichert die Audiodaten als 16-Bit Integer in eine WAV-Datei
    write(wav_filename, user_parameters["sample_rate"], (audio_data * 32767).astype(np.int16))
    print(f"WAV-Datei '{wav_filename}' erfolgreich erstellt!")

    # WAV-Datei per E-Mail versenden
    send_email_with_attachment(user_parameters["receiver_email"], user_parameters["email_subject"], user_parameters["email_body"], wav_filename)
    print(f"WAV-Datei '{wav_filename}' erfolgreich per E-Mail versendet!")

So funktioniert das Script

Das Sender-Script verschlüsselt eine Nachricht, wandelt sie in Binärdaten um und erzeugt daraus eine Audiodatei, die dann per E-Mail verschickt wird:

  1. Variablen, die bearbeitet werden müssen: Zu Beginn und auch an einer Stelle weiter unten im Code gibt es Einstellungen, die du vorab unbedingt vornehmen musst. Dazu gehören der geheime Schlüssel (den der Empfänger in seinem Script auch hinterlegen muss), die E-Mail-Adressen, das Passwort aus Gmail und natürlich die zu verschlüsselnde Nachricht selbst.
"encryption_key": "geheimer_schluessel",  # Schlüssel (beide Parteien müssen denselben Schlüssel verwenden)
"sender_email": "Absender-Adresse",  # Absender-E-Mail-Adresse
"sender_password": "App-Passwort",        # App-Passwort für die Absender-E-Mail
"receiver_email": "Empfänger-Adresse",      # Empfänger-E-Mail-Adresse
"email_subject": "Betreff",   # Betreff der E-Mail
"email_body": "Inhalt der E-Mail, z.B. Hier kommt eine verschlüsselte Nachricht für dich.",  # E-Mail-Inhalt
"wav_filename": "message.wav"           # Name der zu speichernden WAV-Datei
 
email_message = "Das Pferd frisst keinen Gurkensalat."  # Die eigentliche Textnachricht, die verschlüsselt und versendet wird
  1. Nachricht mit dem Schlüssel verschlüsseln Die Funktion encrypt_message() verwendet eine einfache XOR-Verschlüsselung, um die Nachricht zu verschlüsseln. Dabei wird jedes Zeichen der Nachricht mit einem Zeichen des Schlüssels kombiniert:
   def encrypt_message(text, key):
       encrypted_message = ""
       for i in range(len(text)):
           encrypted_char = chr(ord(text[i]) ^ ord(key[i % len(key)]))
           encrypted_message += encrypted_char
       return encrypted_message

Diese Methode sorgt dafür, dass sowohl der Sender als auch der Empfänger denselben Schlüssel benötigen, um die Nachricht zu entschlüsseln.

  1. Nachricht in Binärdaten umwandeln Nachdem die Nachricht verschlüsselt wurde, wird sie in Binärdaten umgewandelt, um sie später als Audio darstellen zu können:
   def text_to_binary(text):
       binary_data = ''.join(format(ord(char), '08b') for char in text)
       return binary_data

Jedes Zeichen der Nachricht wird in seine 8-Bit-Binärdarstellung konvertiert, sodass die gesamte Nachricht als eine Folge von Nullen und Einsen dargestellt wird.

  1. Erstellen eines Tons für jedes Bit Die Funktion generate_tone() erstellt einen Sinuston für ein einzelnes Bit (entweder „0“ oder „1“). Diese Töne werden später aneinandergereiht, um die gesamte Nachricht in Audiodaten darzustellen:
   def generate_tone(frequency, duration, sample_rate):
       t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
       return np.sin(2 * np.pi * frequency * t)

Hierbei wird entweder eine Frequenz für „0“ oder eine andere für „1“ verwendet, um die Bits der Nachricht zu unterscheiden.

  1. Nachricht in Audiodaten kodieren Die Funktion encode_to_audio() wandelt die gesamte Binärnachricht in Audiodaten um, indem sie für jedes Bit den entsprechenden Ton erzeugt und diese aneinanderreiht:
   def encode_to_audio(binary_data, bit_duration, sample_rate, freq_0, freq_1):
       audio = np.array([])
       for bit in binary_data:
           if bit == '0':
               audio = np.append(audio, generate_tone(freq_0, bit_duration, sample_rate))
           else:
               audio = np.append(audio, generate_tone(freq_1, bit_duration, sample_rate))
       return audio

Das Ergebnis ist eine Audiodatei, die die verschlüsselte Nachricht repräsentiert.

  1. Erstellen und Versenden der Audiodatei Nachdem die Audiodaten erstellt wurden, wird die Nachricht als .wav-Datei gespeichert und per E-Mail versendet:
   write(wav_filename, sample_rate, (audio_data * 32767).astype(np.int16))

Diese Zeile speichert die Audiodaten als 16-Bit-Integer-Werte in einer WAV-Datei auf deinem Computer, die dann mit der Funktion send_email_with_attachment() per E-Mail versendet wird.

Ergänze das Script nun um deine Daten und hinterlege die Nachricht, die du versenden möchtest. Lass anschließend das Script einmal laufen – im Terminal solltest du die Nachricht lesen können, dass die E-Mail mit der Audio-Datei an deinen Empfänger gesendet wurde:

Und das war es für den Sender – nun zur anderen Seite, dem Empfänger deiner verschlüsselten Nachricht.

Das Script für den Empfänger

Der Empfänger der Nachricht benötigt also ein eigenes Script, das es ihm ermöglicht, die verschlüsselten Audiodaten wieder in Text umzuwandeln. Hier das vollständige Python-Script:

# Verschlüsselte Nachrichten - Script für den Sender
# Pollux Labs, polluxlabs.net

import numpy as np
from scipy.io.wavfile import read

# Parameter, die vom Benutzer bearbeitet werden müssen
user_parameters = {
    "sample_rate": 44100,  # Abtastrate (Hz)
    "bit_duration": 0.1,   # Dauer eines Bits (in Sekunden)
    "freq_0": 1000,        # Frequenz für "0" (Hz)
    "freq_1": 2000,        # Frequenz für "1" (Hz)
    "encryption_key": "geheimer_schluessel",  # Verschlüsselungsschlüssel (beide Parteien müssen denselben Schlüssel verwenden)
    "wav_filename": "message.wav"         # Name der zu lesenden WAV-Datei
}

# Funktion zum Dekodieren der Audiodaten in Binärdaten
def decode_audio_to_binary(audio_data, bit_duration, sample_rate, freq_0, freq_1):
    bit_length = int(sample_rate * bit_duration)
    binary_data = ""

    for i in range(0, len(audio_data), bit_length):
        segment = audio_data[i:i + bit_length]
        # Frequenz analysieren, um festzustellen, ob es sich um ein "0"- oder "1"-Bit handelt
        fft_result = np.fft.fft(segment)
        freqs = np.fft.fftfreq(len(segment), 1 / sample_rate)
        peak_freq = abs(freqs[np.argmax(np.abs(fft_result))])

        if abs(peak_freq - freq_0) < abs(peak_freq - freq_1):
            binary_data += "0"
        else:
            binary_data += "1"

    return binary_data

# Binärdaten in Text umwandeln
def binary_to_text(binary_data):
    text = ""
    for i in range(0, len(binary_data), 8):
        byte = binary_data[i:i + 8]
        if len(byte) == 8:
            text += chr(int(byte, 2))
    return text

# Nachricht entschlüsseln
def decrypt_message(encrypted_text, key):
    # Nachricht entschlüsseln, indem der Schlüssel mit den ursprünglichen Daten kombiniert wird (XOR)
    decrypted_message = ""
    for i in range(len(encrypted_text)):
        decrypted_char = chr(ord(encrypted_text[i]) ^ ord(key[i % len(key)]))
        decrypted_message += decrypted_char
    return decrypted_message

# Hauptprogramm
if __name__ == "__main__":
    # WAV-Datei lesen
    sample_rate, audio_data = read(user_parameters["wav_filename"])
    if audio_data.ndim > 1:
        audio_data = audio_data[:, 0]  # Falls Stereo, nur einen Kanal verwenden
    audio_data = audio_data / 32767.0  # Normalisieren auf den Bereich [-1, 1]

    # Audiodaten in Binärdaten dekodieren
    binary_data = decode_audio_to_binary(audio_data, user_parameters["bit_duration"], user_parameters["sample_rate"], user_parameters["freq_0"], user_parameters["freq_1"])
    print(f"Binärdaten der Nachricht: {binary_data[:64]}...")  # Zeigt die ersten 64 Bits der Nachricht (für Debugging)

    # Binärdaten in verschlüsselten Text umwandeln
    encrypted_message = binary_to_text(binary_data)

    # Nachricht entschlüsseln
    decrypted_message = decrypt_message(encrypted_message, user_parameters["encryption_key"])
    print(f"Entschlüsselte Nachricht: {decrypted_message}")

Auch hier gibt es Parameter, die eingestellt werden können – oder müssen:

user_parameters = {
    "sample_rate": 44100,  # Abtastrate (Hz)
    "bit_duration": 0.1,   # Dauer eines Bits (in Sekunden)
    "freq_0": 1000,        # Frequenz für "0" (Hz)
    "freq_1": 2000,        # Frequenz für "1" (Hz)
    "encryption_key": "geheimer_schluessel",  # Verschlüsselungsschlüssel (beide Parteien müssen denselben Schlüssel verwenden)
    "wav_filename": "message.wav"         # Name der zu lesenden WAV-Datei
}

Allen voran natürlich der geheime Schlüssel: Dieser muss unbedingt mit jenem übereinstimmen, den der Sender in seinem Script zum Verschlüsseln verwendet hat.

Aber auch die Parameter sample_rate, bit_duration und die Frequenzen müssen mit den Einstellungen des Senders übereinstimmen. Der Dateiname der wav_filename muss dem Namen der per E-Mail empfangenen Audio-Datei entsprechen – also vor im Script angepasst werden, bevor es ausgeführt wird.

So funktioniert das Script

Das Empfänger-Script liest also die Audiodatei, dekodiert die darin enthaltene Nachricht und entschlüsselt sie. Hier die einzelnen Schritte:

  1. WAV-Datei lesen Das Script beginnt mit dem Einlesen der Audiodatei mithilfe der Funktion scipy.io.wavfile.read(). Dabei wird die Abtastrate und die Audiodaten extrahiert:
   sample_rate, audio_data = read(user_parameters["wav_filename"])
   if audio_data.ndim > 1:
       audio_data = audio_data[:, 0]  # Falls Stereo, nur einen Kanal verwenden
   audio_data = audio_data / 32767.0  # Normalisieren auf den Bereich [-1, 1]

Diese Normalisierung ist notwendig, um die Audiodaten auf einen Bereich zwischen -1 und 1 zu skalieren.

  1. Audiodaten in Binärdaten dekodieren Die Funktion decode_audio_to_binary() analysiert die Audiodaten und konvertiert sie zurück in eine Binärfolge. Dabei wird die Fourier-Transformation verwendet, um die Frequenzen der einzelnen Segmente zu analysieren und zu entscheiden, ob es sich um ein Bit „0“ oder „1“ handelt:
   def decode_audio_to_binary(audio_data, bit_duration, sample_rate, freq_0, freq_1):
       bit_length = int(sample_rate * bit_duration)
       binary_data = ""

       for i in range(0, len(audio_data), bit_length):
           segment = audio_data[i:i + bit_length]
           fft_result = np.fft.fft(segment)
           freqs = np.fft.fftfreq(len(segment), 1 / sample_rate)
           peak_freq = abs(freqs[np.argmax(np.abs(fft_result))])

           if abs(peak_freq - freq_0) < abs(peak_freq - freq_1):
               binary_data += "0"
           else:
               binary_data += "1"

       return binary_data

Diese Funktion durchläuft die Audiodaten in Segmenten und bestimmt für jedes Segment, ob es sich um eine „0“ oder „1“ handelt.

  1. Binärdaten in Text umwandeln Nachdem die Audiodaten in Binärdaten umgewandelt wurden, werden diese in den ursprünglichen Text konvertiert. Hierbei wird jeder 8-Bit-Block in ein Zeichen umgewandelt:
   def binary_to_text(binary_data):
       text = ""
       for i in range(0, len(binary_data), 8):
           byte = binary_data[i:i + 8]
           if len(byte) == 8:
               text += chr(int(byte, 2))
       return text

So wird der verschlüsselte Text aus den Binärdaten wiederhergestellt.

  1. Nachricht entschlüsseln Die entschlüsselte Nachricht wird mit der Funktion decrypt_message() wieder in den Klartext umgewandelt. Dazu wird derselbe Schlüssel verwendet, der auch beim Verschlüsseln benutzt wurde:
   def decrypt_message(encrypted_text, key):
       decrypted_message = ""
       for i in range(len(encrypted_text)):
           decrypted_char = chr(ord(encrypted_text[i]) ^ ord(key[i % len(key)]))
           decrypted_message += decrypted_char
       return decrypted_message

Diese Methode führt eine XOR-Operation auf jedes Zeichen des verschlüsselten Textes durch, um die ursprüngliche Nachricht wiederherzustellen.

  1. Ergebnis anzeigen Schließlich wird die entschlüsselte Nachricht auf der Konsole ausgegeben:
   print(f"Entschlüsselte Nachricht: {decrypted_message}")

Damit erhält der Empfänger die ursprünglich gesendete Nachricht im Klartext in seinem Terminal:

Falls der Empfänger jedoch einen falschen Schlüssel in seinem Script verwendet, klappt es mit dem Entschlüsseln nicht. So sieht die gleiche Nachricht aus, wenn am Ende des Schlüssels zwei Zeichen fehlen:

Die Nachricht beginnt zwar korrekt, weil der Anfang des Schlüssels mit jenem des Senders übereinstimmt. Sie „zerfällt“ dann aber zu Kauderwelsch, da der Schlüssel des Empfängers, wie gesagt, zu kurz ist und also zu früh wieder die ersten Zeichen des Schlüssels verwendet werden. Wenn der Schlüssel überhaupt nicht jenem des Senders entspricht, bleibt die Textnachricht vollständig unlesbar.

Wie geht es weiter?

Du kannst nun also Nachrichten verschlüsselt als Audio versenden und dir einigermaßen sicher sein, dass sie nur jemand entschlüsseln kann, der ein geeignetes Script und vor allem den richtigen Schlüssel dafür besitzt. Wie könnten Verbesserungen aussehen? Du hast vielleicht schon bemerkt, dass die erzeugten WAV-Dateien recht groß sind – die relative kurze Nachricht aus dem Beispiel oben hat bereits 2,6 MB.

Hier könnte eine Konvertierung in das MP3-Format weiterhelfen, um sicherzugehen, dass deine Nachricht nicht zu groß für den Anhang einer E-Mail ist.

]]>
Musik mit künstlicher Intelligenz komponieren https://polluxlabs.net/python-tutorials-und-projekte/musik-mit-kuenstlicher-intelligenz-komponieren/ Wed, 17 Apr 2024 08:27:56 +0000 https://polluxlabs.net/?p=16360 Musik mit künstlicher Intelligenz komponieren Weiterlesen »

]]>
Mit KI kannst du mittlerweile eine Vielzahl von Medien erzeugen: natürlich Texte, mit denen alles anfing, aber auch Bilder und Videos. Eine faszinierende Idee war aber auch immer die Komposition von Musik mit künstlicher Intelligenz – eine Kunstform, die uns täglich begleitet und gleichzeitig zutiefst an menschliches Kreativität gebunden zu sein scheint.

Ich finde, das ist sie nach wie vor, auch wenn KI massive Fortschritte in der Erzeugung (Imitation?) von Musik gemacht hat. Wie auch immer man dazu stehen möchte – spannend ist das Thema ohne Frage. In diesem Artikel stelle ich einige Möglichkeiten und interessante Projekte vor.

Musik mit Udio komponieren

Am Anfang vieler KI-Anwendungen steht ein Prompt – so auch beim Tool Udio. Die Webseite dieses Anbieters erinnert auf den ersten Blick etwas an Spotify. Du findest dort zahlreiche, nach Genres sortierte Songs von anderen Nutzern, die du dir vorab schon mal anhören kannst, um herauszufinden, was Udio so leistet, um Musik mit künstlicher Intelligenz zu produzieren.

Musik mit künstlicher Intelligenz auf udio.com komponieren

Wenn du selbst eine Song erstellen (lassen) möchtest, musst du dich zunächst registrieren. Aktuell ist das nur mit einem Google-, Discord- oder X-Konto möglich. Anschließend kannst du im Feld ganz oben deinen Prompt eintragen und mit Klick auf Create die Musikproduktion starten.

Ich habe mit folgendem Prompt versucht, einen „autofahrttauglichen“ Softrock-Song zu erstellen:

A softrock song that you would have heard in the 90s while taking a long drive on the highway. Male voice, 70s Walker Brothers influence.

Das Ergebnis kannst du dir hier anhören. Bevor du allerdings einen Song wie diesen mit gut 2 Minuten Länge erstellt hast, gibt es noch etwas mehr zu tun. Udio erstellt zunächst eine Art Preview von etwas mehr als 30 Sekunden. Diesen Schnipsel kannst du dann anschließend erweitern, indem du ein weitere Teile wie ein passendes Intro oder Outro erstellen und „drankleben“ lässt. Klicke hierfür neben dem Song auf den Button Extend und wähle die gewünschte Erweiterung.

Das klappt erstaunlich gut, denn einen unnatürlichen Übergang hörst du zwischen den Teilen nicht. Allerdings habe ich es nicht geschafft, dem Song eine richtige Struktur aus Intro, Strophe und Refrain zu geben. Vielmehr führen die Erweiterungen (Sections) das Lied immer weiter in eine Richtung, die kein wirkliches Ziel zu haben scheint. Ein menschlicher Künstler würde hier sicherlich anders vorgehen. Du kannst allerdings auch den sogenannten Manual Mode aktivieren, der dir mehr Möglichkeiten gibt, mit dem zugrundeliegenden Sprachmodell zu interagieren.

In den Songs wird natürlich auch gesungen – auf Stimme und Text kannst du hierbei Einfluss nehmen. Erstere kannst du direkt im Prompt versuchen, näher zu bestimmen. Den gewünschten Gesangstext kannst du (auch hinter dem Button Extend) hinterlegen. Deinem Shoegaze-Track mit vertonten Angeboten von Hornbach steht also nichts mehr im Wege.

Wenn du mit deinem Ergebnis zufrieden bist, kannst du deinen Song auch auf Udio veröffentlichen oder einen Link zum Anhören erstellen und teilen.

Musik mit künstlicher INtelligenz – und einem Plattenspieler

Ein spannendes Projekt zum Thema stammt von Arvind Sanjeev: Hier werden über Druckknöpfe gewünschte Attribute wie Lo-Fi oder Happy und Musikstile wie Dance oder Metal eingestellt. Außerdem kann die Geschwindigkeit und die Länge des Musikstücks vorgegeben werden. Anschließend erstellt das Gerät mit Hilfe von Metas MusicGen einen passenden Track, der dann direkt abgespielt wird. Der Plattenspieler auf der linken Seite kann dann genutzt werden, um den Song vor- oder zurückzuspulen, die Geschwindigkeit zu verändern – oder um darauf zu scratchen.

SPIN Synthesizer mit künstlicher Intelligenz von MusicGen

In der Kiste stecken neben dem Plattenspieler ein Arduino Mega, ein Raspberry Pi – und jede Menge Arbeit. Das Ergebnis ist ein Gerät, das die abstrakte künstliche Intelligenz mit einem haptischen Interface verbindet und sie so nachvollziehbar macht. Ob es praxistauglich für die Musikproduktion ist? Vermutlich nicht. Es ist vielmehr der künstlerische Versuch, neue Technologie in unsere erlernte Lebenswelt „hineinzuholen“ und erfahrbar zu machen. Einen ähnlichen Ansatz hat das Wählscheiben-Telefon mit integriertem ChatGPT, das du hier auf Pollux Labs findest.

Weitere Informationen zur Plattenspielerkiste mit MusicGen und seiner Entstehung findest du bei CreativeApplications.Net

]]>
Bilder analysieren und beschreiben lassen mit künstlicher Intelligenz https://polluxlabs.net/raspberry-pi-projekte/bilder-analysieren-und-beschreiben-lassen-mit-kuenstlicher-intelligenz/ Mon, 25 Mar 2024 08:55:39 +0000 https://polluxlabs.net/?p=16232 Bilder analysieren und beschreiben lassen mit künstlicher Intelligenz Weiterlesen »

]]>
Dass du mit Hilfe von ChatGPT bzw. DALL-E Bilder erzeugen kannst, weißt du sicherlich bereits schon. Aber es geht auch andersherum: Mit Vision von OpenAI kannst du Bilder analysieren – also herausfinden, was darauf zu sehen ist. Und: Das funktioniert auch mit Videos.

In diesem Projekt lernst du, wie du mit Python und der API von OpenAI

Was ist OpenAI Vision?

Üblicherweise kommunizierst du mit ChatGPT oder anderen Sprachmodellen über einen Text-Prompt. Du sendest eine Anforderung oder Frage – und die KI antwortet dir. Mit GPT-4 gibt es jedoch auch die Möglichkeit, zusätzlich zum Text auch ein Bild mitzusenden. Du kannst also zum Beispiel fragen, was auf dem Bild zu sehen ist. Damit machst du dir die multimodalen Eigenschaften zunutze, die dir ermöglichen, verschiedene Medientypen zu kombinieren.

Das Vision zugrunde liegende Modell gpt-4-vision-preview kannst du aktuell (März 2024) nur über die API von OpenAI nutzen. Hierfür benötigst du einen Account bei OpenAI und einen API-Key. Wie du beides erstellst, erfährst du in diesem Tutorial. Um mit der API zu interagieren, eignet sich Python. Hierfür stellt OpenAI eine Bibliothek zur Verfügung, mit der du die gewünschten Funktionen unkompliziert aufrufen kannst.

Ein einzelnes Bild beschreiben lassen

Als erstes Beispiel soll ein einzelnes Bild dienen, das du per API an ChatGPT sendest und von der KI beschreiben lässt. Dieses Bild ist lokal auf deinem Rechner gespeichert. Um es zu übertragen, konvertierst du es zunächst in das Format Base64.

Zusammen mit dem kodierten Bild sendest du deinen Prompt mit – die Frage, was auf dem Bild zu sehen ist. Nach wenigen Sekunden erhältst du die Antwort zurück, die du dann in der Konsole ausgeben kannst. Hier ein Beispiel eines Bilds eines Panthers auf dem Mond und darunter die Interpretation von ChatGPT:

Ein Panther auf dem Mond

Das sieht ChatGPT in dem Bild:

Das ist ein fiktives Bild, das eine Katze in einem Astronautenanzug darstellt. Die Katze steht auf einer unebenen, mondähnlichen Oberfläche, und im Hintergrund ist ein großer erdähnlicher Planet mit verschiedenen Monden und Sternen sowie Galaxien im Weltraum zu sehen. Es handelt sich um eine künstlerische Darstellung, die Elemente aus der Science-Fiction-Szene mit einem Hauch von Humor kombiniert, indem sie ein Haustier in den Kontext der Raumfahrt setzt.

Nicht schlecht, oder? Gut, die KI hat aus dem Panther eine Katze gemacht – aber das kann man ihr wohl verzeihen.

Das Python-Script

Um solch eine Bildbeschreibung zu erstellen, benötigst du nicht viel Code. Hier das Script, das ich dafür verwendet habe:

import base64
import requests
from openai import OpenAI
import os

#Fall nötig: Das Verzeichnis auf das setzen, in dem das Script liegt.
os.chdir(os.path.dirname(os.path.realpath(__file__)))

# OpenAI API-Key
api_key = "DEIN API-KEY VON OPENAI"

# Das Bild konvertieren
def encode_image(image_path):
  with open(image_path, "rb") as image_file:
    return base64.b64encode(image_file.read()).decode('utf-8')

# Pfad zum Bild
image_path = "panther.jpeg"

# Den Base64-String erstellen
base64_image = encode_image(image_path)

headers = {
  "Content-Type": "application/json",
  "Authorization": f"Bearer {api_key}"
}

payload = {
  "model": "gpt-4-turbo",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Was ist auf dem Bild zu sehen?"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": f"data:image/jpeg;base64,{base64_image}"
          }
        }
      ]
    }
  ],
  "max_tokens": 300
}

response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
print(response.json()["choices"][0]["message"]["content"])

Das obige Script orientiert sich an einem Beispiel von OpenAI.

Bevor du das Script laufen lässt, stelle zunächst sicher, dass du die benötigten Bibliotheken installierst hast. Trage außerdem deinen API-Key von OpenAI ein. Dann benötigst du noch den Pfad zum Bild, das du analysieren und beschreiben lassen möchtest. Trage diesen hinter image_path = ein. Falls dein Bild im gleichen Verzeichnis liegt, wie dein Script – Python dieses jedoch nicht findet, kann die Zeile ganz oben unterhalb der Moduleinbindungen hilfreich sein. Damit setzt du das Verzeichnis auf jenes, in dem dein Script gespeichert ist.

Weiter unten im Script findest du den Prompt, der deine Anweisung bzw. Frage zum Bild enthält. Hier Was ist auf dem Bild zu sehen? Je nachdem, was du genau vorhast oder wissen möchtest, kannst du diesen Prompt natürlich anpassen. Wenn du also zum Beispiel wissen möchtest, welche Farben die Blumen auf einer Wiese haben, passe den Prompt entsprechend an.

Damit die Beschreibung von ChatGPT nicht zu ausschweifend und kostspielig wird, kannst du mit max_tokens noch eine maximale Anzahl an verwendeten Tokens festlegen.

Ein Video analysieren

Was mit einem einzelnen Bild geht, funktioniert auch mit einem Video – da ein solches nichts anderes ist als aneinander gereihte Fotos. Und so stellst du ein Video ChatGPT auch bereit, nämlich Frame für Frame.

Das folgende Script öffnet eine lokal gespeicherte Video-Datei und zerlegt es in einzelne Frames. Anschließend erfolgt die Abfrage bei der API, in der du diese Einzelbilder bereitstellst und ebenfalls deinen Prompt (also deine Frage) mitsendest:

import cv2 #Nicht installiert? -> pip install opencv-python
import base64
import time
from openai import OpenAI
import os

#Fall nötig: Das Verzeichnis auf das setzen, in dem das Script liegt.
os.chdir(os.path.dirname(os.path.realpath(__file__)))

client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "DEIN API-KEY VON OPENAI"))

video = cv2.VideoCapture("DEIN VIDEO.mp4")

base64Frames = []
while video.isOpened():
    success, frame = video.read()
    if not success:
        break
    _, buffer = cv2.imencode(".jpg", frame)
    base64Frames.append(base64.b64encode(buffer).decode("utf-8"))

video.release()
print(len(base64Frames), "frames read.")

PROMPT_MESSAGES = [
    {
        "role": "user",
        "content": [
            "Dies sind Frames eines Videos. Beschreibe, was darin zu sehen ist.",
            *map(lambda x: {"image": x, "resize": 768}, base64Frames[0::50]),
        ],
    },
]
params = {
    "model": "gpt-4-turbo",
    "messages": PROMPT_MESSAGES,
    "max_tokens": 400,
}

result = client.chat.completions.create(**params)
print(result.choices[0].message.content)

Wie du siehst, ist das Script etwas anders aufgebaut als das erste. Hier sendest du deine Abfrage nicht per Request, sondern nutzt die Funktion client. Hinterlege wieder einen API-Key und in der Zeile video = cv2.VideoCapture(„DEIN VIDEO.mp4“) den Dateinamen des Videos, das du analysieren lasse möchtest. Falls es nicht im gleichen Ordner wie dein Script liegt, achte bitte auf den korrekten Pfad.

Im Bereich PROMPT_MESSAGE = [ findest du den Prompt, den du mitsendest. Diesen kannst du wieder an deine Wünsche anpassen. Ebenso gibt es wieder die Einstellung max_tokens – hier kann allerdings eine größere Zahl nötig sein als bei dem einzelnen Bild von vorhin. Wenn die erlaubte Anzahl an Tokens zu gering ist, erhältst du möglicherweise keine vollständige Beschreibung des Videos.

Mit dem Raspberry Pi ein Foto aufnehmen und es beschreiben lassen

Bisher hast du bereits vorhandene Bilder oder Videos verwendet. Du kannst aber natürlich auch ein Foto mit der Kamera am Raspberry Pi aufnehmen und dieses von ChatGPT beschreiben lassen. Diesmal gibst du die Analyse jedoch nicht einfach nur in der Konsole aus, sondern lässt sie dir vorlesen.

Damit baust du dir ein Gerät, das du verwenden könntest, um zum Beispiel dir unbekannte Gegenstände, Gemälde oder Gebäude zu identifizieren. Auch für Menschen mit eingeschränktem oder überhaupt keinem Sehvermögen könnte das eine interessante und hilfreiche Anwendung sein.

Raspberry Pi mit Kamera

Das Projekt aufbauen

Ausgelöst wird die Kamera und die anschließende Analyse durch einen gedrückten Button am Raspberry Pi. Schließe diesen wie folgt an. Einen Pulldown- oder Pullup-Widerstand benötigst du hierbei nicht.

Button am Raspberry Pi

Wie du die Kamera anschließt, habe ich in diesem Projekt zur Objekterkennung am Raspberry Pi beschrieben. Allerdings verwende ich darin noch die Option Legacy Camera, die du nun eigentlich nicht mehr benötigst. Leider war das Thema „Kamera am Raspberry Pi“ eine Zeitlang etwas komplex, weswegen es schwierig ist, eine Patentlösung anzubieten, die für die meisten Versionen von Pi und zugehörigem Betriebssystem passt.

Möglicherweise wirst du hier etwas herumprobieren müssen. Im Folgenden verwende ich das Betriebssystem Debian Bookworm (64 Bit) und die Bibliothek Picamera2. Ob deine Kamera korrekt angeschlossen ist und funktioniert, kannst du übrigens im Terminal schnell testen. Führe dafür einfach den folgenden Befehl aus:

libcamera-still -o test.jpg

Wenn alles funktioniert, erscheint ein Vorschaufenster mit dem aktuellen Kamerabild. In diesem Fall steht dem folgenden Python-Script dann nichts mehr im Wege.

Das Python-Script

Das folgende Script erweitert die hier vorangegangen Programme ein wenig. Zunächst wird die Bildbeschreibung erst ausgeführt, sobald der angeschlossene Button gedrückt wurde. Dann wird die Kamera gestartet, ein Foto aufgenommen und dieses dann an ChatGPT übertragen. Nachdem die Antwort vorliegt, wird diese in Sprache umgewandelt und vorgelesen.

Mehr zum Thema „Text in Sprache umwandeln“ findest du übrigens in diesem Tutorial bei uns. Und noch ein Hinweis: Möglicherweise fragst du dich, was mit deinen aufgenommen Fotos passiert, nachdem du sie an ChatGPT übertragen hast. Laut Angaben von OpenAI werden diese nicht für das Training der KI verwendet. Falls du hier jedoch sichergehen möchtest, solltest du auf die Verwendung dieser Fotos vielleicht lieber verzichten.

Hier das Script:

import cv2 #Nicht installiert? -> pip install opencv-python
import base64
from openai import OpenAI #pip install openai
import os
from picamera2 import Picamera2 #pip install picamera2
import RPi.GPIO as GPIO
import pygame #pip install pygame
import time
from pathlib import Path

GPIO.setmode(GPIO.BOARD)
buttonPin = 16
GPIO.setup(buttonPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# Dateiname des aufgenommenen Fotos
image_file = 'image.jpg'

def main():

    # Ein Foto machen
    print("Ich nehme ein Foto auf.")
    picam2 = Picamera2()
    camera_config = picam2.create_still_configuration(main={"size": (1920, 1080)}, lores={"size": (640, 480)}, display="lores")
    picam2.configure(camera_config)
    picam2.start()
    time.sleep(2)
    picam2.capture_file(image_file)
 
    client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "DEIN OPENAI API-KEY"))

    image = cv2.imread(image_file)
    _, buffer = cv2.imencode(".jpg", image)
    base64Image = base64.b64encode(buffer).decode("utf-8")

    print("Ich beschreibe das Foto.")

    PROMPT_MESSAGES = [
        {
            "role": "user",
            "content": [
                "Dies ist ein Foto. Beschreibe, was darauf zu sehen ist.",
                {"image": base64Image, "resize": 768},
            ],
        },
    ]
    params = {
        "model": "gpt-4-turbo",
        "messages": PROMPT_MESSAGES,
        "max_tokens": 200,
    }

    result = client.chat.completions.create(**params)
    description = result.choices[0].message.content
    print(description)

    #Vertonung
    speech_file_path = Path(__file__).parent / "vision.mp3"
    response = client.audio.speech.create(
    model="tts-1",
    voice="alloy",
    input=description
    )
    response.stream_to_file(speech_file_path)
    
    pygame.init()
    pygame.mixer.init()
    pygame.mixer.music.load(speech_file_path)
    pygame.mixer.music.play()
    while pygame.mixer.music.get_busy():
        pass
    pygame.quit()

if __name__ == "__main__":
    while True:
        buttonState = GPIO.input(buttonPin)
        if buttonState == GPIO.LOW: 
            main()
        else:
            print(".")

Wie du siehst, kommen hier noch ein paar weitere Bibliotheken ins Spiel. Wie du sie mit Pip im Terminal installiert, steht als Kommentar jeweils dahinter.

Sobald du alles vorbereitet hast, starte das Script (Kopfhörer bzw. Lautsprecher nicht vergessen). Nachdem du den Button gedrückt hast, sollte das Foto übertragen werden und dir die Bildbeschreibung vorgelesen werden. Hab ein bisschen Geduld, so richtig schnell wird das leider nicht funktionieren – aber es sollte meistens deutlich unter einer Minute dauern.

]]>
Deine persönlichen Radio-Nachrichten auf dem Raspberry Pi https://polluxlabs.net/raspberry-pi-projekte/deine-persoenlichen-radio-nachrichten-auf-dem-raspberry-pi/ Fri, 15 Mar 2024 09:12:31 +0000 https://polluxlabs.net/?p=16173 Deine persönlichen Radio-Nachrichten auf dem Raspberry Pi Weiterlesen »

]]>
Aktuelle Nachrichten selbst zu lesen ist nicht immer möglich – manchmal sind sie vorgelesen gerade praktischer. Nur informiert dich das Radio üblicherweise nur zur vollen Stunde. Dieses Raspberry Pi Projekt schafft Abhilfe: Du besorgst dir die aktuellen Nachrichten von tagesschau.de, fasst sie mit ChatGPT radiotauglich zusammen und lässt sie dir vorlesen.

Mit diesem Projekt lernst du, wie du in Python mit Web Scraping Inhalte von Webseiten herunterlädst, wie du ChatGPT per API verwendest und Texte vertonen lassen kannst. Außerdem erfährst du, wie du per Python-Script MP3s erzeugst und diese auf deinem Raspberry Pi abspielst.

Aufbau des Raspberry Pis

Deine eigene Nachrichtensendung soll auf Knopfdruck starten – hierfür benötigst du einen Button, den du an die Pins des Raspberry Pis anschließt. Orientiere dich hierbei an folgender Skizze:

Button am Raspberry Pi

Einen Pullup- bzw. Pulldown-Widerstand benötigst du hier nicht, das erledigt dein Raspberry Pi intern. Neben dem Button benötigst du noch einen Lautsprecher, über den du die vertonten Nachrichten ausgeben kannst. Hierfür eignen sich z.B. Modelle, die du per 3,5mm Klinkenstecker direkt an den Audioausgang anschließen kannst.

Der API-Key von OpenAI

Falls du noch keinen Account bei OpenAI und auch noch keinen API-Key hast, musst du beides noch schnell einrichten, bevor du ChatGPT und die Funktion zum Vertonen von Texten nutzen kannst. In diesem Tutorial erfährst du, wie.

Im folgenden Python-Script kannst du dann deinen API-Key eintragen, um die Features von OpenAI verwenden zu können.

Das Python-Script

Kommen wir zum Code des Projekts. Hier führst du mehrere Funktionen aus – um die aktuellen Nachrichten von tagesschau.de zu laden, um sie zu kürzen und „radiotauglich“ zu machen, und um sie vorlesen zu lassen.

Hier zunächst das vollständige Script:

import requests
from bs4 import BeautifulSoup
from openai import OpenAI
from pathlib import Path
import pygame
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)
buttonPin = 16
GPIO.setup(buttonPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

def main():
    client = OpenAI(
      api_key="DEIN API-KEY",
    )

    url = 'https://www.tagesschau.de/'

    def getNews():
        nonlocal url
        response = requests.get(url)
        soup = BeautifulSoup(response.text, 'html.parser')
        links = soup.find_all('a', class_='teaser__link')
        for link in links:
            link['href'] = url + link['href']
        return links[:5]

    def getArticle(link):
        response = requests.get(link.get('href'))
        soup = BeautifulSoup(response.text, 'html.parser')
        headline = soup.find('meta', property='og:title')['content'] + '\n'
        paragraphs = soup.find_all('p')
        text = ""
        for paragraph in paragraphs:
            if paragraph.find_parent('div', class_='teaser-absatz__teaserinfo') is None and paragraph.find_parent('div', class_='teaser-xs__teaserinfo') is None:
                text += paragraph.get_text() + '\n'
        return headline, text

    def get_summary(text):
        completion = client.chat.completions.create(
        model="gpt-3.5-turbo", 
        messages=[
        {"role": "system", "content": "Du schreibst Nachrichten fürs Radio."},
        {"role": "user", "content": "Fasse den folgenden Text zusammen: {}".format(text)}]
        )
        summary_text = headline + completion.choices[0].message.content
        return summary_text

    def speech(summary_text):
        speech_file_path = Path(__file__).parent / "news.mp3"
        response = client.audio.speech.create(
        model="tts-1",
        voice="alloy",
        input=summary_text
        )
        response.stream_to_file(speech_file_path)
        pygame.init()
        pygame.mixer.init()
        pygame.mixer.music.load(speech_file_path)
        pygame.mixer.music.play()
        while pygame.mixer.music.get_busy():
            pass
        pygame.quit()

    news_links = getNews()
    for link in news_links:
        headline, text = getArticle(link)
        summary_text = get_summary(text)
        speech(summary_text)

if __name__ == "__main__":
    while True:
        buttonState = GPIO.input(buttonPin)
        if buttonState == GPIO.LOW: 
            main()
        else:
            print(".")

So funktioniert das Script

Sobald du den Button gedrückt hast, wird die Funktion main() aufgerufen. Den Code hierfür findest du ganz am Ende des Scripts. Innerhalb von main() werden mehrere verschachtelte Funktionen definiert, die jeweils für einen bestimmten Teil des Prozesses verantwortlich sind.

Die Funktion getNews() sendet eine GET-Anfrage an eine vordefinierte URL (in unserem Fall ‚https://www.tagesschau.de/‘), analysiert die HTML-Antwort, um alle Links mit der Klasse teaser__link zu finden, und gibt die ersten fünf dieser Links zurück.

Die Funktion getArticle(link) nimmt einen dieser Links als Argument, sendet eine GET-Anfrage an die URL des Links und analysiert ebenso die HTML-Antwort, um die Überschrift und den Text des Artikels zu extrahieren. Dazu sucht sie den meta-Tag mit der Eigenschaft og:title für die Überschrift und alle p-Tags für den Text. Anschließend werden die Überschrift und der Text zurückgegeben.

Die Funktion get_summary(text) nimmt den Text als Argument und verwendet ChatGPT, um eine Zusammenfassung des Textes zu erstellen. Anschließend werden die Überschrift des Artikels und die generierte Zusammenfassung miteinander verknüpft und zurückgegeben.

Die Funktion speech(summary_text) nimmt den zusammengefassten Text als Argument und verwendet die OpenAI-API, um den Text in Sprache umzuwandeln. Anschließend wird der vertonte Text in einer Datei gespeichert und mit pygame abgespielt.

Die benötigten Module

Du benötigst du folgenden Module bzw. Bibliotheken, damit das Script läuft:

import requests
from bs4 import BeautifulSoup
from openai import OpenAI
from pathlib import Path
import pygame
import RPi.GPIO as GPIO

Falls du BeautifulSoup, OpenAI und PyGame noch nicht auf deinem System installiert sind, hole das mit den folgenden Befehlen im Terminal nach:

pip install beautifulsoup4
pip install openai
pip install pygame

Die Bibliothek Beautiful Soup verwendest du fürs Web Scraping. Das bedeutet, dass du hiermit die Texte einer beliebigen Webseite auslesen und in deinem Script weiterverwenden kannst. Mit dem Modul von OpenAI greifst du auf deren Services zu und PyGame verwendest du für die Tonausgabe. Die anderen Module sollten bereits verfügbar sein.

Nachdem du eine Button an deinem Raspberry Pi angebracht und die benötigten Module installiert hast, trage deinen API-Key ein und starte das Python-Script. Nach wenigen Sekunden sollte deine persönlichen Radio-Nachrichten starten.

Möchtest du doch lieber „echtes“ Radio hören? In diesem Tutorial lernst du, wie du dir ein ESP32 Internetradio baust.

]]>
Text To Speech mit Python – So vertonst du Texte https://polluxlabs.net/raspberry-pi-projekte/text-to-speech-mit-python-so-vertonst-du-texte/ Mon, 13 Nov 2023 12:54:54 +0000 https://polluxlabs.net/?p=15278 Text To Speech mit Python – So vertonst du Texte Weiterlesen »

]]>
In diesem Tutorial lernst du zwei Methoden kennen, mit denen du in Python Text in gesprochene Sprache umwandeln kannst. Mit Text to Speech kannst in deinen Projekten zum Beispiel eine Sprachausgabe umsetzen.

Die erste Möglichkeit ist die Python-Bibliothek gTTS, mit der du kostenlos Texte vertonen lassen kannst. Dieses Modul habe ich im Projekt ChatGPT im Telefon eingesetzt. Als zweite Methode lernst du eine API-Funktion von openAI kennen. Diese Variante ist kostenpflichtig – allerdings hört sich das Ergebnis hierfür auch weit besser an.

Text to Speech mit gTTS (Google Text-to-Speech)

Wenn dein Projekt keine astreine Aussprache erfordert, ist die Bibliothek gTTS eine gute Wahl. Die Qualität ist nicht schlecht, allerdings hakt es bei der Aussprache oft bei Abkürzungen oder die Betonung von Satzteilen kommt durch das ein oder andere Komma durcheinander. Dafür kannst du mit diesem Python-Modul den Google-Service kostenlos verwenden – was sicherlich ein gutes Argument für einen Test ist.

Installiere zunächst die Bibliothek mit dem Befehl

pip install gtts

Um die Sprachausgabe zu testen, reichen drei Zeilen Python-Code:

from gtts import gTTS

tts = gTTS('Hello, world. This is a first test.')
tts.save('hello.mp3')

Nachdem du das kleine Script ausgeführt hast, öffne die Datei hello.mp3 und lausche dem Ergebnis. Bist du zufrieden?

Du kannst übrigens auch deutsche Texte vertonen lassen. Füge hierfür den Parameter lang=’de‘ hinzu:

tts = gTTS('Hallo, das ist einer erster Test.', lang='de')

Das war im Prinzip schon alles. Wenn du wissen möchtest, wie du die MP3 direkt mit deinem Python-Script abspielen kannst, wirf einen Blick in das oben verlinkte Projekt. Weitere Infos über gTTS erhältst du hier.

Text To Speech mit openAI

Wenn dir eine gute Sprachqualität ein paar Cent wert ist, ist OpenAI einen Versuch wert. Neben dem allseits bekannten ChatGPT findest du dort auch eine API-Funktion, mit der du Text vertonen lassen kannst. Die Integration in dein Python-Script ist dabei ähnlich einfach wie mit gTTS. Allerdings kostet der Service derzeit (November 2023) 0,015 € je 1.000 Zeichen – was ein recht überschaubarer Preis ist. Die aktuelle Preisliste findest du hier unter Audio models.

Wenn du noch nicht mit OpenAI experimentiert hast, erfährst du in diesem Tutorial, wie du dort ein Konto und einen API-Key erstellst.

Nachdem du die Bibliothek openai (mit pip install openai) installiert hast, binde sie in deinem Python-Script ein. Zusätzlich benötigst du noch das Modul pathlib der Bibliothek Path, das aber bereits vorinstalliert ist.

from pathlib import Path
from openai import OpenAI

Anschließend hinterlegst du deine API-Key von OpenAI:

client = OpenAI(
  api_key="DEIN API-KEY",
)

Und schon kann es mit der Vertonung losgehen. Du gibst zunächst an, wie die erzeugte MP3 heißen soll – hier speech.mp3:

speech_file_path = Path(__file__).parent / "speech.mp3"

Anschließend legst du ein paar Parameter fest: Zunächst das Modell – hier hast du die Wahl zwischen tts-1 und tts-1-hd. Letzteres hat eine etwas höhere Qualität und ist auch teurer. Für die allermeisten Anwendungen dürfte das einfachere Modell jedoch ausreichen. Der Parameter voice gibt vor, welche Stimme verwendet werden soll. Derzeit gibt es sechs Stimmen, die du hier probehören kannst. Dort findest du auch aktuelle Informationen und Updates zu Text to Speech mit OpenAI.

Zuletzt fehlt nur noch der Text, den du vertonen lassen möchtest und der Befehl zum Speichern der MP3:

response = client.audio.speech.create(
  model="tts-1",
  voice="alloy",
  input="Das Pferd frisst keinen Gurkensalat."
)

response.stream_to_file(speech_file_path)

Und das war schon alles. Führe das Script aus – sobald es fertig ist, findest du im gleichen Ordner die Datei speech.mp3 mit deiner Sprachausgabe. Hier nun das gesamte Script:

from pathlib import Path
from openai import OpenAI

client = OpenAI(
  api_key="DEIN API-KEY",
)

speech_file_path = Path(__file__).parent / "speech.mp3"
response = client.audio.speech.create(
  model="tts-1",
  voice="alloy",
  input="Das Pferd frisst keinen Gurkensalat."
)

response.stream_to_file(speech_file_path)

Mit den oben beschriebenen Bibliotheken und Services hast du nun zwei Methoden zur Hand, wie du in deinem Projekt Text to Speech anwenden kannst. Ob dir eine kostenlose Vertonung reicht, oder du etwas qualitativ hochwertigeres benötigst, hängt natürlich vom Einsatzgebiet ab.

]]>
Kochen mit ChatGPT und REWE-Angeboten https://polluxlabs.net/python-tutorials-und-projekte/kochen-mit-chatgpt-und-rewe-angeboten/ Fri, 03 Nov 2023 00:06:20 +0000 https://polluxlabs.net/?p=15215 Kochen mit ChatGPT und REWE-Angeboten Weiterlesen »

]]>
Dass ChatGPT mittlerweile mit einem Bild deines Kühlschrankinhalts kochen kann, ist bekannt. Aber wie wäre es einmal mit einem Gericht, dessen Zutatenliste nur aus Sonderangeboten deines nächstgelegenen REWE-Markts besteht? In diesem Projekt probierst du genau das aus: Du fragst die aktuellen REWE-Angebote per API ab und lässt ChatGPT daraus Rezeptideen erstellen – Kochen mit ChatGPT.

Zum Einsatz kommen hierbei zwei Python-Scripts – das erste, um die ID deines Wunsch-Supermarkts herauszufinden und die zweite für die Abfrage der Angebote und die Erstellung der Rezepte. Wenn du möchtest, kannst du letzteres auch automatisieren: Auf deinem Raspberry Pi könnte ein Cronjob jeden Montag die aktuellen Angebote abrufen und ChatGPT dir daraus sieben Rezepte für die ganze Woche erstellen.

Noch ein Hinweis vorab: Bei diesem Projekt handelt es sich natürlich um eine Spielerei – ob die von ChatGPT vorgeschlagenen Gerichte wirklich schmecken, ist leider nicht so ganz sicher. Aber bei den ersten Tests kam schon ansprechende Speisen heraus, z.B. Süßkartoffel-Kürbis-Auflauf, Mediterrane Hähnchenschenkel mit frischen Kräutern und Zitronen-Butter oder Rouladen nach Landhaus-Art. Sowohl die Zutatenliste auch die Anweisungen zur Zubereitungen klangen nicht abwegig. Ein Versuch ist es allemal Wert – und dieser Versuch erweitert auf jeden Fall deine Fähigkeiten.

Finde die ID deines REWE-Markts heraus

Bevor du die Angebote des REWE-Markts deiner Wahl abrufen kannst, benötigst du den marketCode dieses Markts. Den kannst du ganz leicht mit einem kleinen Python-Script herausfinden:

import requests
import json

# Trage hier deinen Standort ein
search_term = 'Karlsruhe'
url = f'https://www.rewe.de/api/marketsearch?searchTerm={search_term}'

# Stelle die Anfrage an die API.
response = requests.get(url)

# Überprüfe, ob die Anfrage erfolgreich war (HTTP Status Code 200).
if response.status_code == 200:
    # Parse die Antwort als JSON.
    data = response.json()

    # Schön formatierte Ausgabe des JSON.
    print(json.dumps(data, indent=4))
else:
    print('Fehler bei der Anfrage:', response.status_code)

Um die Märkte an deinem Standort zu finden, trage diesen in die Variable search_term ein – in meinem Fall ist das Karlsruhe. Wenn du das Script nun ausführst, erhältst du die Antwort als JSON. Hier die ersten beiden Einträge einer möglichen Antwort der API:

{
        "wwIdent": "831008",
        "isReweDortmund": false,
        "companyName": "REWE Ponzer GmbH & Co. oHG",
        "contactStreet": "Hans - Sachs - Str. 8",
        "contactZipCode": "76133",
        "contactCity": "Karlsruhe",
        "marketHeadline": "REWE Markt",
        "openingInfo": {
            "willOpen": {
                "onDay": 5,
                "at": "07:00"
            }
        }
    },
    {
        "wwIdent": "840913",
        "isReweDortmund": false,
        "companyName": "REWE Christopher Lannert oHG",
        "contactStreet": "Josef-Schofer-Str. 14",
        "contactZipCode": "76187",
        "contactCity": "Karlsruhe",
        "marketHeadline": "REWE Markt",
        "openingInfo": {
            "willOpen": {
                "onDay": 5,
                "at": "07:00"
            }
        }
    },

Gleich der jeweils erste Key wwIdent ist die ID bzw. marketCode, den du später benötigst. Suche dir also den gewünschten Markt aus der Liste heraus und notiere dir die ID.

Aktuelle Angebote finden

Bevor es mit dem nächsten Python-Script losgehen kann, musst du noch die Bibliothek cloudscraper installieren. Diese benötigst du, das die API von REWE eigentlich keine automatisierten Abfragen zulässt. Mit dieser Bibliothek kannst du diese Sperre allerdings umgehen. Achte deshalb bitte darauf, keinen „Unfug“ anzustellen und z.B. zahllose Anfragen an die API zu stellen.

Um die Bibliothek zu installieren, gib im Terminal bzw. in der Konsole folgenden Befehl ein:

pip install cloudscraper

Außerdem benötigst du noch die Bibliothek openai, mit der du die API von ChatGPT ansteuern kannst. Diese installierst du wie folgt:

pip install openai

Nun kann es mit dem Script losgehen. Zunächst bindest du die beiden genannten Bibliotheken ein und hinterlegst deine gefundene ID sowie die URL für die Abfrage:

import cloudscraper
from openai import OpenAI

# Deine ID, hier ein Beispiel aus Karlsruhe
market_id = '831008'
# Die Basis-URL der API
url = f'https://mobile-api.rewe.de/api/v3/all-offers?marketCode={market_id}'

Anschließend bereitest du cloudscraper vor, erstellst einen leeren String, in den die gefundenen Sonderangebote geschrieben werden – und erstellst eine Liste der Angebotskategorien, die überhaupt für Rezepte in Frage kommen. Es gibt natürlich auch Angebote in den Kategorien Haushalt, Tierfutter, Spirituosen etc., mit denen wir aber hier nichts anfangen können.

# Erstellen ein Cloudscraper-Objekt
scraper = cloudscraper.create_scraper()

# Stelle die GET-Anfrage
response = scraper.get(url)

# Initialisiere einen leeren String für die Titel der Angebote
titles_string = ''

# Eine Liste der gewünschten Kategorietitel
desired_categories = {
    'Frische & Kühlung',
    'Süßes & Salziges',
    'Obst & Gemüse',
    'Nahrungsmittel',
    'Tiefkühl'
}

Nun fehlt nur noch die eigentliche Abfrage. Hier stellst du sicher, dass in der Variablen titles (für die Namen der angebotenen Artikel) nur jene aus den vorgegebenen Kategorien gespeichert werden.

# Überprüfe  den Statuscode der Antwort
if response.status_code == 200:
    # Wenn der Statuscode 200 ist, war die Anfrage erfolgreich
    # Konvertiere die Antwort in JSON
    data = response.json()
    
    # Extrahiere die Angebote, die den gewünschten Kategorietiteln entsprechen
    titles = [
        offer['title']
        for category in data['categories']
        for offer in category['offers']
        if 'rawValues' in offer and 'categoryTitle' in offer['rawValues']
        and offer['rawValues']['categoryTitle'] in desired_categories
    ]
    
    # Erstelle einen String mit den gefilterten Titeln, getrennt durch Kommas
    titles_string = ', '.join(titles)
    
    # Ausgabe des Strings
    print("Gefilterte Titel:", titles_string)
else:
    # Wenn der Statuscode nicht 200 ist, gab es ein Problem mit der Anfrage
    print(f'Fehler: {response.status_code}')

Rezepte erstellen lassen mit ChatGPT

Nun folgt der zweite Teil des Scripts. Hier fragst du ChatGPT über die API nach Rezeptideen, die auf den gefundenen Sonderangeboten basieren. Hierfür benötigst du einen API-Key von OpenAI. In diesem Tutorial erfährst du, wie du dir den benötigten Key erstellst.

Du hinterlegst im Script also deinen Key und erstellst gleich danach die Abfrage:

client = OpenAI(
  api_key="DEIN API-KEY",
)

print("Ich erstelle Gerichte...")
completion = client.chat.completions.create(
#model="gpt-3.5-turbo", 
model="gpt-4",
messages=[
{"role": "system", "content": "Du bist ein KI-Koch, der aus vorgegebenen Zutaten Rezepte für Gerichte entwirft."},
{"role": "user", "content": "Es folgt eine Liste von Zutaten. Kreiere hieraus 3 Rezepte für leckere Gerichte. Gehe davon aus, dass die Küchen-Basics wie Salz, Pfeffer, Öl, Butter etc. bereits vorhanden sind. Hier die Liste: {}".format(titles_string)}]
)

print(completion.choices[0].message.content)

Du findest im obigen Code zwei Zeilen, mit denen du auswählen kannst, ob du das Modell 3.5 oder die neuere Version 4 verwenden möchtest. Kommentiere einfach die nicht gewünschte Version aus.

Als Anweisung (system) an ChatGPT legst du fest, dass die KI als Ideengeber für Rezepte fungieren soll. Mit dem eigentlichen Prompt (user) legst du dann fest, was du möchtest. Im obigen Beispiel sind es drei Rezepte, für die übliche Zutaten wie Salz und Pfeffer enthalten sein dürfen, auch wenn sie nicht in den Angeboten zu finden sind. An diesen Prompt hängst du dann einfach die Liste der Angebote an.

Hier hast du natürlich einiges an Spielraum. So könntest du z.B. nur vegetarische Gerichte entwerfen lassen und ChatGPT Unverträglichkeiten mitteilen.

Die Antwort der künstlichen Intelligenz sieht dann beispielsweise folgendermaßen aus:

Rezept 1: Rinderrouladen mit Apfel-Rotkohl und Maronen

Zutaten:
- Rinder-Rouladen
- Petersilie
- Rote Tafeläpfel
- REWE Beste Wahl Apfelrotkohl
- REWE Bio Gekochte Maronen

1. Die Rinderrouladen flach ausbreiten, mit Salz und Pfeffer würzen und mit gehackter Petersilie bestreuen. Die Rouladen aufrollen und mit Küchengarn befestigen.
2. Die Rouladen in einem großen Topf mit Öl scharf anbraten und anschließend beiseite stellen.
3. Die Äpfel schälen, vierteln, entkernen und klein schneiden. Zusammen mit dem Apfelrotkohl in den Topf geben und ca. 5 Minuten dünsten.
4. Die Rinderrouladen zurück in den Topf geben und bei niedriger Hitze 60 Minuten köcheln lassen.
5. 10 Minuten vor Ende der Kochzeit die gekochten Maronen hinzufügen.
6. Abschmecken und servieren.

Klingt doch halbwegs plausibel, oder? Eine Beilage wäre vielleicht noch gut und dass der Rotkohl in den gleichen Topf wie die Rouladen soll, ist auch nicht ganz einleuchtend. Auch wenn du die Rezepte nicht 1:1 übernehmen solltest, erhältst du mit diesem Projekt recht brauchbare Ideen für Gerichte, die deinen Geldbeutel schonen. Ich wünsche dir jedenfalls schon einmal guten Appetit!

Hier nun das vollständige Python-Script:

import cloudscraper
from openai import OpenAI

# # Deine ID, hier ein Beispiel aus Karlsruhe
market_id = '831008'
# Die Basis-URL der API
url = f'https://mobile-api.rewe.de/api/v3/all-offers?marketCode={market_id}'

# Erstellen ein Cloudscraper-Objekt
scraper = cloudscraper.create_scraper()

# Stelle die GET-Anfrage
response = scraper.get(url)

# Initialisiere einen leeren String für die Titel der Angebote
titles_string = ''

# Eine Liste der gewünschten Kategorietitel
desired_categories = {
    'Frische & Kühlung',
    'Süßes & Salziges',
    'Obst & Gemüse',
    'Nahrungsmittel',
    'Tiefkühl'
}

# Überprüfe  den Statuscode der Antwort
if response.status_code == 200:
    # Wenn der Statuscode 200 ist, war die Anfrage erfolgreich
    # Konvertiere die Antwort in JSON
    data = response.json()
    
    # Extrahiere die Angebote, die den gewünschten Kategorietiteln entsprechen
    titles = [
        offer['title']
        for category in data['categories']
        for offer in category['offers']
        if 'rawValues' in offer and 'categoryTitle' in offer['rawValues']
        and offer['rawValues']['categoryTitle'] in desired_categories
    ]
    
    # Erstelle einen String mit den gefilterten Titeln, getrennt durch Kommas
    titles_string = ', '.join(titles)
    
    # Ausgabe des Strings
    print("Gefilterte Titel:", titles_string)
else:
    # Wenn der Statuscode nicht 200 ist, gab es ein Problem mit der Anfrage
    print(f'Fehler: {response.status_code}')


# Mit ChatGPT Rezepte erstellen
client = OpenAI(
  api_key="DEIN API-KEY",
)

print("Ich erstelle Gerichte...")
completion = client.chat.completions.create(
#model="gpt-3.5-turbo", 
model="gpt-4",
messages=[
{"role": "system", "content": "Du bist ein KI-Koch, der aus vorgegebenen Zutaten Rezepte für Gerichte entwirft."},
{"role": "user", "content": "Es folgt eine Liste von Zutaten. Kreiere hieraus 3 Rezepte für leckere Gerichte. Gehe davon aus, dass die Küchen-Basics wie Salz, Pfeffer, Öl, Butter etc. bereits vorhanden sind. Hier die Liste: {}".format(titles_string)}]
)

print(completion.choices[0].message.content)
  
]]>
Leg los mit CircuitPython https://polluxlabs.net/arduino-tutorials/leg-los-mit-circuitpython/ Mon, 12 Oct 2020 12:30:12 +0000 https://polluxlabs.net/?p=2972 Leg los mit CircuitPython Weiterlesen »

]]>

Suchst du einen leichten Zugang in die Welt der Microcontroller und Elektronikprojekte? Oder bist du schon ein alter Hase und hast einfach Lust auf etwas Neues? Es gibt eine Menge Gründe, CirycuitPython auszuprobieren!

In diesem Artikel erfährst du, was CircuitPython ist und was du brauchst, um damit durchzustarten. Wir schreiben zusammen etwas Python-Code und lassen ein paar LEDs wilde Sachen machen. 🙂

Was ist CircuitPython?

Das New Yorker Unternehmen Adafruit hat im Sommer 2017 ihre „neue“ Programmiersprache vorgestellt: CircuitPython. Hierbei handelt es sich um einen sogenannten Fork von MicroPython, einer anderen Sprache, die ebenso für die Programmierung von Microcontrollern entwickelt wurde. Beide Programmiersprachen basieren auf Python 3 – CircuitPython wurde jedoch mit dem Ziel entwickelt, besonders einsteigerfreundlich zu sein.

Python gilt als leicht zu erlernende Programmiersprache und wird mittlerweile auch bereits in der Schule unterrichtet. Dabei ist Python nicht nur etwas für Einsteiger – auch komplexe Projekte im Bereich der künstlichen Intelligenz werden z.B. mit Python realisiert.

Welche Vorteile hat CircuitPython?

Abgesehen davon, dass Python relativ leicht zu lernen ist, hat der Einsatz von CircuitPython noch weitere Vorteile.

Vermutlich hast du bereits in der Arduino IDE Sketches in C++ geschrieben und auf dein Board geladen. Dann weißt du, dass jede Änderung im Code mit einem längeren Update des Boards verbunden ist: Der Sketch wird kompiliert und dann vollständig auf den Microcontroller geladen – was ganz schön lange dauern kann.

Anders bei CircuitPython: Wenn du dein Board per USB an deinen Computer anschließt, wird es als Laufwerk erkannt. Hierauf befindet sich der Python-Code z.B. in der Datei code.py – diese Datei kannst du theoretisch mit jedem Text-Editor öffnen und verändern. Sobald du deine Änderungen gespeichert hast, resettet sich dein Board automatisch und läuft mit dem neuen Code – eine Sache von wenigen Sekunden.

Der große Unterschied hierbei ist, dass C++ kompiliert wird und Python (also auch CircuitPython) interpretiert. Wie bitte? Um nicht den Rahmen dieses Artikel zu sprengen, lies bitte hier mehr über Kompilieren und Interpretieren, wenn dich das Thema interessiert.

Die REPL

Das klingt schon ziemlich schnell, aber es geht noch schneller. Wenn auf deinem Board CircuitPython läuft, kannst du mit ihm über die REPL (engl. Read–eval–print loop) kommunizieren. Das heißt, du kannst Befehle direkt an deinen Microcontroller senden, die dieser dann sofort ausführt.

Das ist besonders praktisch zum Debuggen, also um schnell mal auszuprobieren, ob eine LED richtig angeschlossen ist oder eine Funktion so funktioniert, wie du es dir vorgestellt hast. Mit der Arduino IDE und C++ kann das mitunter frustrierend sein, da du auch für kleine Änderungen im Sketch alles wieder neu kompilieren und hochladen musst.

Die REPL im Mu Editor mit CircuitPython

Später lernst du in diesem Artikel den Mu Editor kennen. Dann werden wir genauer auf die REPL eingehen.

Und die Nachteile?

Natürlich hat der Einsatz von CircuitPython auch Nachteile. Ein gewichtiger ist der Support mit Bibliotheken: Adafruit und die Community haben bereits für viele Sensoren und Bauteile passende Bibliotheken veröffentlicht und stellen diese selbstverständlich kostenfrei zur Verfügung. An die Menge, die dir in der Arduino IDE zur Verfügung steht, kommen sie aber noch nicht heran.

Da CircuitPython jedoch eine noch relativ junge Technologie ist, sind wir davon überzeugt, dass sich das im Laufe der Zeit ändern wird. Bereits jetzt veröffentlicht Adafruit regelmäßig neue Bundles mit Bibliotheken, die dir das Leben leichter machen.

Stichwort Geschwindigkeit: Die Geschwindigkeit beim Entwickeln ist bei CircuitPython zwar höher, dafür können Programme jedoch langsamer laufen als es beim kompilierten Code in C++ der Fall ist. Aber dieser Unterschied dürfte bei den meisten Hobby-Anwendungen kaum ins Gewicht fallen.

Der passende Microcontroller

Der einfachste Weg, mit CircuitPython und Microcontrollern zu experimentieren, ist, ein speziell dafür ausgelegtes Board zu kaufen. Adafruit hat hier eine fast schon überwältigende Menge an verschiedenen Boards in vielen Größen und für viele Anwendungsbereiche produziert.

Du kannst CircuitPython aber auch auf einigen Arduino-Boards wie dem Zero oder dem MKR Zero zum Laufen bringen. In der Dokumentation von Adafruit erfährst du mehr darüber.

In diesem Artikel verwenden wir das Board Metro M0 Express von Adafruit. Es hat dieselben Maße wie ein Arduino UNO und verfügt über ähnlich viele Analog- und Digitalpins. Außerdem hat es 4 LEDs und einen NeoPixel an Bord und verfügt über 2MB Speicher. Genug Platz für deinen Code, Dateien und Bibliotheken.

Alle Boards, die CircuitPython unterstützen, findest du in einer Übersicht von Adafruit.

Vorbereitungen

Du hast dich entschlossen, mit CircuitPython loszulegen? Großartig! Bevor du anfängst, musst du allerdings noch etwas Zeit in Vorbereitungen stecken.

Zunächst solltest du dir die passende Firmware für dein Board, die aktuellen Bibliotheken und einen passenden Editor herunterladen und installieren.

Die Firmware

Suche in der Übersicht von Adafruit nach deinem Board und klicke darauf. Anschließend siehst du die verfügbaren Versionen der Firmware. Achte darauf, die neueste stable Version herunterzuladen – in unserem Beispiel die Version 5.3.1

Firmware Metro M0 Express

Schließe nachdem Download dein Board per USB an deinem Computer an. Als nächstes musst du es in den Boot-Modus versetzen: Das machst du, indem du zweimal kurz hintereinander den Reset-Button auf dem Board drückst.

Adafruit weist darauf hin, dass das in der „richtigen“ Geschwindigkeit erfolgen soll – wie auch immer, wenn es geklappt hat, findest du im Explorer (oder Finder auf deinem Mac) ein neues Laufwerk. Der Name des Laufwerks setzt sich aus dem Boardnamen und „BOOT“ zusammen. In unserem Fall heißt es also METROBOOT.

Das Board im Boot-Modus im Finder

Ziehe nun die Datei, die du vorhin heruntergeladen hast, auf dieses Laufwerk. Damit installierst du die Firmware. Nach wenigen Sekunden sollte das Laufwerk automatisch ausgeworfen werden und dafür ein anderes mit dem Namen CIRCUITPY erscheinen.

Wenn das der Fall ist, hat alles funktioniert und dein Board ist bereit. 🙂 Falls es nicht klappt, wirf einen Blick in die Dokumentation von Adafruit – hier werden einige weitere Hilfestellungen gegeben.

Die Bibliotheken

Jetzt wo dein Board bereit ist, fehlen noch die Bibliotheken. Wie eingangs erwähnt, gibt es bereits für viele Anwendungen eine Bibliothek, die dir Arbeit abnimmt.

Adafruit bietet hier ganze Bundles an, die du dir hier herunterladen kannst. Lade dir von dort das Bundle herunter, das deiner Firmware-Version entspricht. Wenn du also eine Firmware in der Version 5.x installiert hast benötigst du das Bibliotheken-Bundle mit derselben Versionsnummer.

Entpacke die heruntergeladene Datei und öffne den Ordner. Im Unterordner lib findest du nun alle verfügbaren Bibliotheken. Suche dir die aus, die du benötigst und kopiere sie in den gleichnamigen Ordner des Laufwerks CIRCUITPY. Wenn dein Board genug Speicher besitzt, kannst du auch einfach alle Bibliotheken dort rüberkopieren.

Bibliotheken für CircuitPython auf dem Metro M0 Express

Wenn du auf Probleme stößt, konsultiere die Dokumentation von Adafruit zum Thema Bibliotheken. Hier werden recht viele Sonderfälle besprochen.

Examples

Aus der Arduino IDE kennst du sicherlich die Beispiele, die den meisten Bibliotheken beiliegen. Diese sind recht nützlich, um herauszufinden, welche Funktionen eine Bibliothek bietet und wie du diese verwendest.

Diese Beispiele gibt es auch für CircuitPython. Auf der Seite, von der du das Bibliotheken-Bundle heruntergeladen hast, kannst du unter Bundle Examples eine ZIP-Datei mit Beispielen herunterladen.

Wie du diese Beispiele auf deinem Board ausführst, sehen wir gleich. Zunächst fehlt jedoch noch der passende Editor.

Der Mu Editor

Um Code in CircuitPython schreiben zu können, benötigst du natürlich einen Editor. Hier reicht im Prinzip der einfachste Text Editor – wir möchten dir jedoch den Mu Editor ans Herz legen. Der ist gratis, einsteigerfreundlich und für CircuitPython ausgelegt. So findest du darin z.B. einen Seriellen Monitor und Plotter wie du es vermutlich schon von der Arduino IDE gewohnt bist. Außerdem kannst du hier auch die oben beschriebene REPL problemlos verwenden.

Lade dir die aktuelle Version hier von der offiziellen Seite für dein Betriebssystem herunter.

Erste Schritte

Öffne nun den Mu Editor. Als nächstes schauen wir uns die wichtigsten Funktionen an. Danach schreibst du auch schon deinen ersten Code in Python und bringst ihn auf deinem Board zum Laufen.

Oberfläche des Mu Editors

Im oberen Bereich findest du eine Leiste mit Funktionen:

Modus: Hier kannst du einstellen, für welchen Zweck du den Mu Editor verwenden möchtest. Unserer heißt Adafruit CircuitPython.

Neu: Erstellt eine neue leere Datei.

Laden & Speichern: Das ist sicherlich klar. 🙂 Ein Hinweis vorab: Wenn dein Board deinen Code automatisch starten soll, musst du den Dateinamen cody.py verwenden.

Seriell & Plotter: Diese beiden kennst du sicherlich schon von der Arduino IDE. Hier kannst du wie gewohnt Daten einsehen und Statements ausgeben, die dir beim Debuggen helfen.

Prüfen: Hiermit kannst du deinen Code auf Fehler checken lassen.

Die REPL öffnen und verwenden

Um die REPL zu öffnen und direkt mit deinem Board interagieren zu können, öffne zunächst über den entsprechenden Button oben den Seriellen Monitor. Drücke anschließend gleichzeitig Strg + C und danach eine beliebige Taste. Nun öffnet sich die REPL:

Die REPL im Mu Editor

Zeit für einen kurzen Test: Kopiere den folgenden Code, füge ihn in deiner REPL ein und drücke Enter:

import board
import digitalio
import time
 
led = digitalio.DigitalInOut(board.D13)
led.direction = digitalio.Direction.OUTPUT

Jetzt kannst du direkt die Onboard-LED anschalten, indem du folgendes eingibst und wieder Enter drückst:

led.value = True

Ist sie angegangen? Dann schalte sie versuchsweise wieder aus, indem du led.value auf False setzt. Hinweis: Auf den meisten kompatiblen Boards kannst du die interne LED über den Pin D13 ansteuern. Bei einigen ist es jedoch D17 und einige wenige haben keine interne LED.

So speicherst du dein Programm auf dem Board

Die REPL ist toll, um schnell etwas zu testen. In den meisten Fällen wirst du jedoch ein reguläres Programm in CircuitPython schreiben und direkt auf deinem Board abspeichern.

Dein Board sucht automatisch nach einer Datei mit dem Namen code.py. Wenn es keine findet, hält es Ausschau nach der Datei main.py und führt diese aus. Heißt konkret: Speichere das Programm, das ausgeführt werden soll unter dem Namen code.py direkt auf dem Laufwerk CIRCUITPY deines Boards ab.

Immer wenn dein Board hier eine Änderung feststellt – weil du den Code im Mu Editor aktualisiert und gespeichert hast – rebootet es und führt den neuen Code aus. Das ganze dauert in der Regel nur wenige Sekunden.

Dein erstes Programm in CircuitPython

Jetzt wird es Zeit, dein erstes Programm zu schreiben, auf deinem Board abzuspeichern und auszuführen. Auch für dieses Beispiel soll erst einmal eine blinkende LED reichen.

Schnapp dir ein Breadboard, eine LED und einen Vorwiderstand und baue folgendes auf:

Ein erster Test mit CircuitPython und Adafruit Metro Express

Kopiere nun folgenden Code in eine leere Datei in deinem Mu Editor und speichere sie als code.py ab.

import board
import digitalio
import time
 
led = digitalio.DigitalInOut(board.D1)
led.direction = digitalio.Direction.OUTPUT
 
while True:
    led.value = True
    time.sleep(0.5)
    led.value = False
    time.sleep(0.5)

Deine LED sollte nun im Halbsekundentakt an- und wieder ausgehen. Werfen wir nun einen Blick auf die einzelnen Teile des Codes.

Zunächst bindest du drei Bibliotheken ein so wie du es aus der Arduino IDE kennst. Viele Bibliotheken sind in extra Dateien ausgelagert und müssen von dir in den Ordner lib auf deinem Board gespeichert werden, bevor du sie verwenden kannst.

Die drei Bibliotheken in diesem Beispiel sind jedoch Teil von CircuitPython. Das heißt, du musst nichts weiter tun, bevor du sie verwenden kannst, außer sie einzubinden:

import board
import digitalio
import time

Die Bibliothek board benötigst du für den Zugriff auf deine Hardware, digitalio kümmert sich um die Inputs und Outputs des Boards und mit time kannst du dein Programm „schlafen legen“ – ähnlich wie du das mit delay() in C++ machst.

Anschließend legst du den Pin der LED (D1) und seine „Richtung“ (OUPUT) fest. Auch das kennst du aus der Arduino IDE von der Funktion pinMode().

led = digitalio.DigitalInOut(board.D1)
led.direction = digitalio.Direction.OUTPUT

Zuletzt erstellst du einen While-Loop, der ununterbrochen läuft. Hier schaltest du die LED mit led.value = True ein, wartest eine halbe Sekunde und schaltest sie für eine weitere halbe Sekunde wieder aus.

while True:
    led.value = True
    time.sleep(0.5)
    led.value = False
    time.sleep(0.5)

Spiele an den Werten etwas herum, um zu sehen, wie sich die Intervalle der LED verändern. Wenn du dein Programm speicherst, sollten deine Änderungen nach wenigen Sekunden sichtbar werden.

Wie geht es weiter?

Du hast nun alles, was du brauchst, um mit CircuitPython loszulegen. Zeit für deine Experimente. Schaue als nächstes in den Bibliotheken nach, für welche deiner Bauteile und Sensoren du hier etwa passendes findest. Wirf anschließend einen Blick in die Beispiel-Codes, die jeder Bibliothek beiliegen und beginne deine Abenteuer mit CircuitPython!

]]>
MicroPython installieren auf dem ESP8266 & ESP32 https://polluxlabs.net/esp8266-projekte/micropython-installieren-auf-dem-esp8266-esp32/ Tue, 25 Feb 2020 20:52:18 +0000 https://polluxlabs.net/?p=1086 MicroPython installieren auf dem ESP8266 & ESP32 Weiterlesen »

]]>
Hier erfährst du, was MicroPython ist, welche Vorteile dir diese Programmiersprache bietet und wie du sie auf deinem ESP8266* oder ESP32* installierst.

Was ist MicroPython?

MicroPython ist angelehnt an und kompatibel zu Python 3 und speziell für die Programmierung von Microcontrollern ausgelegt. Die Sprache ist dem regulären Python sehr ähnlich – das heißt, wenn du bereits mit Python programmieren kannst, kannst du das auch mit MicroPython.

Da diese Sprache darauf ausgelegt ist, unter eingeschränkten Bedingungen – nämlich auf Microcontrollern mit wenig Speicherplatz – zu arbeiten, besitzt MicroPython nicht alle Bibliotheken von Python. Die für die Programmierung von ESP8266 und ESP32 sind natürlich an Bord – insbesondere jene, die du brauchst, um mit den Pins zu arbeiten und dich mit dem Internet zu verbinden.

Welche Vorteile bietet MicroPython?

Python ist eine Programmiersprache, die sowohl leicht zu lernen als auch leicht zu lesen ist. Das gilt auch für MicroPython – wenn du etwas Python beherrschst und schon auf „richtigen“ Computern programmiert hast, fällt dir der Einstieg mit MicroPython leicht. Hier findest du einen Überblick über wichtige Funktion von MicroPython (Englisch).

Weitere Vorteile sind:

  • Du kannst deinen Microcontroller „live“ programmieren. D.h. über die Shell (bzw. REPL) kannst du deinen Code direkt testen, ohne erst einen ganzen Sketch hochladen zu müssen.
  • Exception und Error-Handling: Du kannst den Umgang mit Ausnahmen und Fehler bereits in deinem Code definieren.

Aber MicroPython hat auch Nachteile im Vergleich zur Arduino IDE und C, denn hier gibt es für viele Bauteile bereits Bibliotheken, die du einfach installieren, einbinden und verwenden kannst. Mit MicroPython wirst du ab und an etwas länger nach einer geeigneten Lösung suchen müssen.

MicroPython installieren mit der Thonny IDE

Um mit MicroPython auf deinem ESP8266* oder ESP32* loslegen zu können, musst du deinen Microcontroller mit einer passenden Firmware flashen. Hierfür gibt es mehrere Möglichkeiten. Eine recht einfache ist der Editor Thonny IDE. Das Tolle: Thonny ist für Anfänger bestens geeignet und du kannst auch gleich deinen Microcontroller damit programmieren.

Lade dir zunächst die neueste Version von Thonny hier herunter und starte die Installation.

Die Firmware herunterladen

Als nächstes benötigst du die aktuelle Firmware. Diese findest du hier auf der offiziellen Seite von MicroPython. Wähle den entsprechenden Abschnitt für deinen Controller und lade dir die aktuelleste (latest) Version herunter, indem du auf den Dateinamen mit der Endung .bin klickst. Mit dieser Datei flashst du gleich deinen Microcontroller.

Schließe nun deinen Microcontroller wie gewohnt über USB an deinen Computer an. Nun öffne die Thonny IDE.

Klicke als Erstes Menü Run auf Configure interpreter. Dort findest du im Dropdown-Menü mehrere Optionen – auch jeweils eine für den ESP8266 und den ESP32. Wenn du die passende Option gewählt hast, kannst du unter Port or WebREPL den USB-Port wählen, an dem dein Microcontroller angeschlossen ist.

Klicke nun auf den Link unten rechts Install or update MicroPython.

Wähle unter Port noch einmal den richtigen USB-Port aus und wähle unter Firmware die Datei, die du gerade heruntergeladen hast.

Mit einem Klick auf Install geht es los! Auf deinem Microcontroller wird MicroPython installiert. Nach wenigen Sekunden sollte das erledigt sein und du kannst die drei Fenster wieder schließen, bis du wieder auf der Oberfläche der Thonny IDE bist.

So funktioniert MicroPython und die Thonny IDE

Die Oberfläche der Thonny IDE besteht (neben dem Menü) aus zwei Fenstern. Im oberen schreibst du dein Python-Programm, dass über den grünen „Play“-Button auf deinen ESP8266 oder ESP32 hochlädst.

Im unteren Fenster findest du die Shell, mit der quasi in Echtzeit mit deinem Microcontroller interagieren kannst.

Wenn du einen ESP8266 angeschlossen hast, trage hinter die drei >>> in der Shell probeweise – Zeile für Zeile – folgenden Code ein und drücke nach jeder Zeile Enter:

from machine import Pin
Pin(2, Pin.OUT).value(0)

Nun sollte die interne LED auf deinem Controller leuchten. Wenn du in die Klammern hinter value eine 1 einträgst, geht sie wieder aus. Seltsamerweise verhält sich dieser Code beim ESP8266 „falsch herum“ – eine 1 schaltet den Pin auf HIGH, eine 0 auf LOW. Beim ESP32 ist das wiederum wie gewohnt.

Wie geht es weiter?

Jetzt hast du das grundlegende Setup, um deinen Microcontroller mit MicroPython zu programmieren. Erforsche als nächstes, was du hiermit alles anstellen kannst! 🙂

Hier findest du ESP8266 Projekte, die du nachbauen oder von denen du dich inspirieren lassen kannst.

Wenn MicroPython doch nicht das Richtige für dich ist, lerne hier CircuitPython kennen.

]]>