Kleine Programmierhilfe für arduino benötigt - Relais per mqtt schalten

  • Ich habe ein Programm, mit dem ich 3 Servos über mqtt (un iobroker) ansteuern kann.

    Die Servos wollte ich gerne während sie nicht beötigt werden, stromlos machen.

    Dazu wollte ich ein Relais (einen Ausgang z. B. D1 vom Nodemcu) über einen mqtt Wert, den ich im iobroker eingebe, schalten.

    Kann mir da jemand syntaxmäßig helfen???

    Hier das Flash-Programm (arduino):


  • Hmm, auch ein normales Relais braucht zum schalten Strom, nur bistabile nicht. Es fragt sich also, ob diese Lösung zweckmäßig ist.

    Ansonsten...

    Hast du den Code selbst zusammengestellt, kennst ihn also genau?


    Spendiere einfach in reconnect() einen weiteren Subscriber und baue die Abarbeitung der Nachricht in MQTTCallback() ein!


    Btw. wenn du zwischen den if Anweisungen jeweils noch ein else spendierst, sollte die Abarbeitung im Mittel etwas schneller erfolgen, weil dann nicht zwingend alle Stringvergleiche abgearbeitet werden. Ich würde eh ein Datenfeld aus Topic-String und Funktionszeiger zusammenstellen und statt der if eine kleine Schleife bauen. Mehr Datenstruktur, weniger (übersichtlichere) Ablaufstruktur. ;-) Das ist aber für dein Anliegen unwesentlich.

  • ehrlich gesagt, ich kenne mich mit der Syntax nicht aus,

    Den Code habe ich im IE gefunden und er funktioniert, eine Optimierung ist mir nicht so wichtig.

    Ich will nur z. B. von D1 einen den Zustand via iobroker schalten können - 0 und 1.

    Leider kenne ich deine Fachbegriffe nicht - vielleicht kannst du mir konkret mit Code-Schnipsel helfen?

    hab das unten mal probiert, könnte es so gehen????


    Und dann bräuchte ich noch das Schalten des Ausganges D1.

    Ich schätze mal D1 als Ausgang definieren - wie?

    Und dann If then - wie?

  • Wenn du absolut keine Ahnung von den Programmiersprachen C bzw. C++ hast, ist es etwas gewagt, ein solches Programm für deine Zwecke anzupassen.

    Prinzipiell sind deine notierten Zeilen geeignet, die du einzufügen hast, aber

    • In Zeile 5 ist im Topic (Der Text zwischen den Anführungszeichen) ein Verdreher - Realis -> Ralais. So kann es nicht funktionieren. Bitte korrigieren!
    • Die Zeilen 5 bis 8 müssen innerhalb MQTTCallback stehen, was sie vermutlich auch tun.
    • Zeile 12 muss innerhalb reconnect stehen, ...

    "Innerhalb" bedeutet: an passenden Stellen zwischen der ersten geschweiften Klammer auf nach dem Funktionsnamen (hier MQTTCallback und reconnect) und der schließenden geschweiften Klammer am Ende der jeweiligen Funktion.


    Ich kenne die Klasse Servo nicht. ServoObject1 bis ServoObject3 sind jedenfalls 3 verschiedene Objekte dieser Klasse. Diese Klasse verfügt über mindestens zwei Methoden, attach und write.

    • attach ordnet dem jeweiligen Servo Objekt einen Ausgang des µC (Mikrocontroller) zu.
    • write dürfte einen Wert seriell über den zugeordneten Ausgang an die Servo Elektronik ausgeben. Dieser Wert ist hier eine Ganzzahl (Typ int) und stellt offensichtlich den Zielwinkel dar.

    Zum schalten eines Relais ist ein solches Objekt nicht vorgesehen und vermutlich auch nicht geeignet. Welche "Anweisungen" zur Verfügung stehen, findest du unter https://www.arduino.cc/reference/en. Für deine Zwecke sind pinMode() und digitalWrite() zweckmäßig/erforderlich. Hierfür suchst du dir einen noch freien Ausgang deines µC Boards aus, analysierst das zu schaltende Relais und schließt es passend an den ausgesuchten Ausgang an. Dazu braucht man zwei Leitungen. Die zweite Leitung ist, je nach Relaisschaltung, entweder mit Masse (GND) oder mit Vcc (+5V oder +3,3V) zu verbinden.


    Für die Pflegbarkeit "deines" Programms ist es zweckmäßig, einen Bezeichner für den Ausgang zu deinem Relais zu definieren, bspw. per

    #define Relais 5 oder als Konstante const int Relais = 5; Beides führt dazu, dass im weiteren Quelltext Relais statt 5 verwendet werden kann.


    Die Funktion setup() wird immer nur einmal nach einem Neustart des µC abgearbeitet. Darin werden einmalige Initialisierungen untergebracht. Das ist hier der Aufruf von pinMode(Relais, OUTPUT), wobei Relais die zuvor definierte Pinnummer des Ausgangs zum schalten des Relais ist. OUTPUT stellt den Pin auf Ausgabe.

    Nun sind noch die Aktivitäten des Subscribers (client) zum schalten des Relais zu erweitern. Dazu ist die Ausgabeanweisung digitalWrite(Pinnummer, HIGH) oder digitalWrite(Pinnummer, LOW) in MQTTCallback einzubauen - am besten statt HIGH und LOW die Payload verwendend, bspw. so:

    Code
    if(strcmp(topic, "ServoControl/Relais/OnOff") == 0) // prüft, ob das MQTT Topic ServoControl/Relais/OnOff lautet.
    {
    digitalWrite(Relais, angle); // Hierfür muss die MQTT Payload entweder "0" oder "1" sein, damit es so funktioniert.
    }

    Es ist nicht schön, hier als Payload-Wert Variable angle zu verwenden, weil ein Relais nicht per Winkelwert geschaltet wird. Ich würde statt angle die Benennung value oder Payload nehmen.

    Die MQTT Nachricht muss lauten:

    Topic = ServoControl/Relais/OnOff, Payload = 0 zum ausschalten oder 1 zum einschalten.


    Dies ist die kürzest mögliche Variante. Es geht besser und letztlich flexibler, wenn in MQTTCallback zuerst an Hand des Topic geprüft wird, ob die Payload ein Winkelwert für die Servos oder ein Wahrheitswert für das Relais ist. Damit verschone ich dich aber besser jetzt. ;-)


    Noch etwas sehr wichtiges:

    Damit die Kommunikation per MQTT gelingt, braucht es irgendwo einen MQTT Broker als zentralen Kommunikationsserver. Die Daten (IP Adresse und Portnummer) dieses Servers sind hier einzutragen:

    Code
    const char* mqtt_server = "XXX"; // <- IP Adresse des Brokers
    const int mqtt_port = XXX; // <- Portnummer, Standard ist 1883

    Ich weiß nicht, ob ioBroker eine Art MQTT Broker Plugin nutzt, ich verwende weder ioBroker noch FHEM noch openHAB. Ich arbeite "bodenständig" mit Mosquitto (MQTT Broker) und NodeRED auf einem Raspberry Pi 3, der 24/7 läuft.


    Falls du den gesamten Quellcode von mir haben möchtest, gegen Gebühr von 1234,56 € :P, dann musst du dich noch einmal entsprechend äußern. Allerdings gehören zum endgültig lauffähigen Programm noch die genaue Kenntnis deiner Schaltung und die MQTT Daten deines Netzwerks.

    Wer eine schnelle und billige Lösung will, muss mit Folgeproblemen rechnen. ;-)

  • herzlichen Dank schonmal für deine Mühe, ich muss mir das morgen in Ruhe zu Gemüte führen.

    Für die perfekte Lösung, da schreckt mich die Gebühr etwas ab ;)

    Aber ich werde bestimmt zurechtkommen.

    Ich wollte noch einmal klarstellen - das Programm läuft ja schon einwandfrei in iobroker - die Servos verrichten ihre Arbeit!

    Die XXXe hab ich ja nur reingemacht, damit ich hier nichts Persönliches freigebe.

    Ich will jetzt "nur" an einer Erweiterung basteln - Relais schalten - und ich meine das müsste prinzipiell ein sehr leichte Aufgabe sein,

    aber der Teufel steckt ja wie so immer im Detail :)

  • Herzlichen Dank!

    Zuerst wollte ich deine Tipps richtig gut umsetzten, bin aber dann doch gescheitert und habe mich zurückgezogen auf das absolut notwendige Minimum.

    Soll heißen, es funktioniert jetzt, auch wenn es sich jetzt sicher nicht um einen "schönen" code handelt - "servo" ist zweckentfremdet und muss als Signalgeber für HIGH/LOW herhalten.

    D1 konnte nicht durch den Stellvertreter "Relais" dargestellt werden.

    Aber was soll`s denn es FUNKTIONIERT und freut mich trotzdem!!!

    So sieht er jetzt aus:

  • Na bitte.

    Das passt doch zu meinen Erklärungen - und es ist durchaus erträglich.

    An einer einzigen Stelle mal in einer solch kleinen Firmware D1 statt Relais zu verwenden, ist tolerierbar.

    Sogar meine Kommentare sind im Quellcode. Das ist gut, damit du verstehend nachsehen kannst, wenn mal noch eine Änderung angestrebt ist.

    Servo ist auch nicht zweckentfremdet, da du das Relais per digitalWrite(...) steuerst.

    Es freut mich, dass du zufrieden bist. Ich bin es letztlich auch. :)