Hi Liebe FHEM-Community,
ich spiele seit ein paar Tagen mit meinem Arduino Mega und meinem Ethernetshield herum.
Mein Ziel ist es einen Sensor zubauen, welcher die Werte an FHEM schickt.
Jetzt scheitere ich schon daran irgendas zum FHEM-Server zu schicken, dabei hatte ich an Telnet gedacht.
Hier mal mein Programm:
/*
Telnet client
This sketch connects to a a telnet server (http://www.google.com)
using an Arduino Wiznet Ethernet shield. You'll need a telnet server
to test this with.
Processing's ChatServer example (part of the network library) works well,
running on port 10002. It can be found as part of the examples
in the Processing application, available at
http://processing.org/
Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13
created 14 Sep 2010
modified 9 Apr 2012
by Tom Igoe
*/
#include <SPI.h>
#include <Ethernet.h>
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 0, 291);
// Enter the IP address of the server you're connecting to:
IPAddress server(192, 168, 0, 220);
// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 23 is default for telnet;
// if you're using Processing's ChatServer, use port 10002):
EthernetClient client;
void setup() {
// start the Ethernet connection:
Ethernet.begin(mac, ip);
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// give the Ethernet shield a second to initialize:
delay(1000);
Serial.println("connecting...");
// if you get a connection, report back via serial:
if (client.connect(server, 7072)) {
Serial.println("connected");
} else {
// if you didn't get a connection to the server:
Serial.println("connection failed");
}
}
void loop() {
// if there are incoming bytes available
// from the server, read them and print them:
if (client.available()) {
char c = client.read();
Serial.print(c);
}
// as long as there are bytes in the serial queue,
// read them and send them out the socket if it's open:
while (Serial.available() > 0) {
char inChar = Serial.read();
if (client.connected()) {
client.print(inChar);
}
}
// if the server's disconnected, stop the client:
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
// do nothing:
while (true);
}
}
192.168.0.220 ist die IP vom FHEM-Server.
Das Programm ist ein Beispiel-Sketch aus der Arduino IDE.
Eigentlich müsste ich jetzt, wenn ich in der Seriellen Eingabe "set Stehlampe on" eingebe, meine Stehlampe einschalten können.
Also der Arduino gibt schonmal ein "connected" aus...
Den FHEM-Server kann ich von meinem Mac problemlos per telnet steuern.
Was mache ich falsch? :-[
Mfg
Philipp ;D
Hi,
also eigentlich gibt es bessere Wege, einen Sensor zu bauen, der Werte an FHEM schickt, aber wenn Du das unbedingt mit Telnet machen willst...
Ich kann Dir nicht sagen, was da genau falsch läuft. Vielleicht solltest Du erst einmal den Sketch ganz stark vereinfachen, so dass er z.B. einmal alle 20 Sekunden "set Stehlampe on\n" oder sowas schickt. Dann in FHEM mal global verbose auf 5 setzen und schauen, ob was ankommt.
Gruß,
Thorsten
Hi Thorsten,
welche Alternativen zu Telnet fallen dir denn ein ?
Mfg
Philipp
Zitat von: EnderPhilipp am 10 April 2017, 11:13:15welche Alternativen zu Telnet fallen dir denn ein ?
Also wenn es unbedingt Ethernet sein muss, dann z.B. mySensors (das Gateway kann selbst Sensor sein), MQTT, Polling per HTTPMOD, ECMD (Ethersex?), eigenes TCP-Protokoll per TCP-Socket,...
Gruß,
Thorsten
Zitat von: Thorsten Pferdekaemper am 10 April 2017, 11:26:55
Also wenn es unbedingt Ethernet sein muss, dann z.B. mySensors (das Gateway kann selbst Sensor sein), MQTT, Polling per HTTPMOD, ECMD (Ethersex?), eigenes TCP-Protokoll per TCP-Socket,...
Gruß,
Thorsten
Das gibt es ja doch ein paar Alternativen...
Kann ich denn das MySensors-Gateway denn auch ohne den Transreceiver verwenden?
MFG
Philipp
falls auf deiner Hardware ESPEasy läuft wäre das auch eine sehr einfache Variante.
kenne aber die Arduino HW zuwenig um das einzuschätzen.
Zitat von: EnderPhilipp am 10 April 2017, 15:09:21
Das gibt es ja doch ein paar Alternativen...
Kann ich denn das MySensors-Gateway denn auch ohne den Transreceiver verwenden?
MFG
Philipp
Sollte gehen, aber vielleicht schaust Du Dir erst mal firmata an (dem Vernehmen nach sollte man aber eher ältere Versionen davon nehmen).
Das einfache Ein- und Ausschalten eines PINs sollte damit sehr einfach gehen.
Gruß, Beta-User
Must DU zum aufbauen der Verbindung wirklich die MAC mit angeben?
Und pert se finde ich es nicht schlecht mit telnet (oder nc) zu arbeiten. HTTP wäre mir dazu gleich schon wieder "zu viel Hochsprache"
EspEasy und Firmata habe ich mir auch schon angeguckt.
EspEasy lässt sich auf meinem ArduinoMega leider nicht installieren.
Und mit Firmata kann ich leider nicht alle meine Sensoren verwenden.
Werde es mal mit MQTT versuchen. :D
Mfg
Philipp
Zitat von: EnderPhilipp am 10 April 2017, 16:47:19
Werde es mal mit MQTT versuchen. :D
...dann ziehe das am besten mal in den MQTT-Bereich um. Ich bin mir sicher, damit machst Du Rince und eisler glücklich.
Gruß,
Thorsten
Rince hat Urlaub :)
Aber die MQTT Einführung Teil 3 sollte genau das Gesuchte sein ::)
Zitat von: Rince am 10 April 2017, 20:25:28
Rince hat Urlaub :)
"Urlaub" bedeutet doch die Abwesenheit von der "Arbeit". Meiner Auffassung nach ist "Arbeit" in diesem Sinne das, womit man Geld verdient. Verdienst Du mit der MQTT-FHEM-Beratung Geld? Ich glaube nicht. Das bedeutet, dass es keine Arbeit sondern im weitesten Sinne Urlaubsbeschäftigung ist.
Also hopp...
SCNR,
Thorsten
Du hast völlig Recht.
Aber das Hemd ist näher als die Jacke oder wie auch immer der Spruch geht.
Auf meiner Urlaubs-ToDo stehen:
1 Arduino Mega, 1 W5100, 2 x BME 220, 16 Relaisboard, FHEM, MQTT Broker, LibreElec und ein Sat IP Konverter.
Das ist für meinen Bruder. Sonst hat der zu Hause kein Licht und kein Fernsehen.
Ich bin sicher, auch für diesen Thread fällt was ab, aber eben erst in einigen Tagen 8)
Davon abgesehen:
Unter dem angesprochenen Teil 3 ist ein vollständiges Codebeispiel, das funktionieren müsste. Philipp müsste es nur in die IDE copy&pasten.
Und mehr Infos rausrücken... welche Sensoren, etwas Quellcode...
Zitat von: Rince am 10 April 2017, 22:21:45
Unter dem angesprochenen Teil 3 ist ein vollständiges Codebeispiel, das funktionieren müsste. Philipp müsste es nur in die IDE copy&pasten.
Und mehr Infos rausrücken... welche Sensoren, etwas Quellcode...
Hi Rince,
ich wollte folgende Sensoren einbauen:
1. Si7021 (Temperatur & Luftfeuchtigkeit)
2. TSL2561 (Helligkeit)
3. Elechouse PN532 (NFC) [Kennt da wer eine gute Bibliothek?]
4. PIR (Bewegung)
5. HC-SR04 (Entfernung)
6. MPR121 (Berührung)
7. ein paar Analoge-Sensoren (Geräusche-Sensor, MQ135 )
Ich habe mir den Beispielcode mal für den
Si7021 und meinen
PIR präpariert, mehr habe ich bisher noch nicht gemacht.
Könnte sich das mal bitte anschauen und sagen, ob da Fehler drin sind?
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include "Adafruit_Si7021.h"
Adafruit_Si7021 sensor = Adafruit_Si7021();
int bewegung=23;
int bewegungsstatus=0;
byte mac[] = { 0xDE, 0xCD, 0xBA, 0xFE, 0xEE, 0xED }; //eine MAC Adresse wählen, darf im eigenen Netz nur 1x vorkommen
IPAddress ip(192, 168, 0, 121); //eine gültige IP Adresse für das eigene Netz
IPAddress server(192, 168, 0, 38); //die Adresse wo der eigene MQTT Broker drauf läuft
void callback(char* topic, byte* payload, unsigned int length) {
// handle message arrived
}
EthernetClient ethClient;
PubSubClient client(ethClient);
long lastReconnectAttempt = 0;
boolean reconnect() {
if (client.connect("Arduino_1", "zuHause/Arduino_1", 0, true, "offline")) {
// Once connected, publish an announcement...
client.publish("zuHause/Arduino_1","online", true);
// ... and resubscribe
client.subscribe("inTopic");
}
return client.connected();
}
static char humidity[15]; //Speicherbereich reservieren um die Fechtigkeit zu speichern
static char temperature[15];
float h = 0.0;
float h_alt = 0.0;
float t = 0.0;
float t_alt = 0.0;
unsigned long previousMillisPIR = 0;
unsigned long previousMillis7021 = 0; //Zählervariable für den S , zählt Millisekunden seit dem letzten Funktionsaufruf nach oben
const long interval = 60000; //60000 Millisekunden aka 60 Sekunden, das Interval wie oft der Sensor überhaupt benutzt wird
void setup()
{
client.setServer(server, 1883);
client.setCallback(callback);
Ethernet.begin(mac, ip);
delay(1500);
lastReconnectAttempt = 0;
Serial.begin(9600);
Serial.println("MQTT - Test!");
sensor.begin();
pinMode(bewegung, INPUT);
}
void loop()
{
if (!client.connected()) {
long now = millis();
if (now - lastReconnectAttempt > 5000) {
lastReconnectAttempt = now;
// Attempt to reconnect
if (reconnect()) {
lastReconnectAttempt = 0;
}
}
} else {
// Client connected
client.loop();
}
unsigned long currentMillis = millis();
//Si7021 Temperature & Humidity
if (currentMillis - previousMillis7021 >= interval) {
previousMillis7021 = currentMillis;
h = sensor.readHumidity(); //Luftfeuchte auslesen
t = sensor.readTemperature(); //Temperatur auslesen
}
// Prüfen ob eine gültige Zahl zurückgegeben wird. Wenn NaN (not a number) zurückgegeben wird, dann Fehler ausgeben.
if (isnan(t) || isnan(h))
{
Serial.println("Si7021 konnte nicht ausgelesen werden");
client.publish("fhem/universalsensor/Arduino","Sensorfehler",true); //true sendet die Nachricht retained, d.h. die Nachricht bleibt solange auf dem Broker, bis etwas neues kommt
}
else if (h == h_alt && t == t_alt)
{
//nix machen
}
else
{
client.publish("fhem/universalsensor/Arduino","online", true);
dtostrf(h,6, 1, humidity);
dtostrf(t,6, 1, temperature);
client.publish("fhem/universalsensor/Humidity",humidity, true);
client.publish("fhem/universalsensor/Temperature",temperature, true);
h_alt = h; //den alten Messwert aufheben
t_alt = t; //um nur bei Veränderung zu reagieren
Serial.print("Luftfeuchte: ");
Serial.print(h);
Serial.print(" %\t");
Serial.print("Temperatur: ");
Serial.print(t);
Serial.println(" C");
}
// PIR
if (currentMillis - previousMillisPIR >= 2000) {
bewegungsstatus=digitalRead(bewegung);
if (bewegungsstatus == HIGH)
{
client.publish("fhem/universalsensor/Bewegugung","on", true);
}
else
{
client.publish("fhem/universalsensor/Bewegugung","off", true);
}
}
}
Und was bedeutet diese Zeile? :
client.connect("Arduino_1", "zuHause/Arduino_1", 0, true, "offline")
Mfg
Philipp :D
Die Zeile heißt:
if (client.connect("Arduino_1", "zuHause/Arduino_1", 0, true, "offline")) {
Wird in der Einführung Teil 3 in epischer Breite beschrieben :)
Schau mal;
https://wiki.fhem.de/wiki/MQTT_Einf%C3%BChrung_Teil_3#Last_Will_.26_Testament
Das ist die exakte Antwort auf deine Frage :)
Und wenn du wissen willst, warum das so komisch aussieht:
http://pubsubclient.knolleary.net/api.html#connect2
Hier bist direkt an der Quelle 8)
Zitat von: Rince am 11 April 2017, 12:42:42
Die Zeile heißt:
if (client.connect("Arduino_1", "zuHause/Arduino_1", 0, true, "offline")) {
Wird in der Einführung Teil 3 in epischer Breite beschrieben :)
Schau mal;
https://wiki.fhem.de/wiki/MQTT_Einf%C3%BChrung_Teil_3#Last_Will_.26_Testament
Das ist die exakte Antwort auf deine Frage :)
Und wenn du wissen willst, warum das so komisch aussieht:
http://pubsubclient.knolleary.net/api.html#connect2
Hier bist direkt an der Quelle 8)
Hätte ich mal genauer gelesen...
Habe das im Code geändert, der sieht jetzt so aus:
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include "Adafruit_Si7021.h"
Adafruit_Si7021 sensor = Adafruit_Si7021();
int bewegung=23;
int bewegungsstatus=0;
byte mac[] = { 0xDE, 0xCD, 0xBA, 0xFE, 0xEE, 0xED }; //eine MAC Adresse wählen, darf im eigenen Netz nur 1x vorkommen
IPAddress ip(192, 168, 0, 121); //eine gültige IP Adresse für das eigene Netz
IPAddress server(192, 168, 0, 38); //die Adresse wo der eigene MQTT Broker drauf läuft
void callback(char* topic, byte* payload, unsigned int length) {
// handle message arrived
}
EthernetClient ethClient;
PubSubClient client(ethClient);
long lastReconnectAttempt = 0;
boolean reconnect() {
if (client.connect("ZimmerSensor", "fhem/universalsensor/Arduino", 0, true, "offline")) {
// Once connected, publish an announcement...
client.publish("fhem/universalsensor/Arduino","online", true);
// ... and resubscribe
client.subscribe("inTopic");
}
return client.connected();
}
static char humidity[15]; //Speicherbereich reservieren um die Fechtigkeit zu speichern
static char temperature[15];
float h = 0.0;
float h_alt = 0.0;
float t = 0.0;
float t_alt = 0.0;
unsigned long previousMillisPIR = 0;
unsigned long previousMillis7021 = 0; //Zählervariable für den S , zählt Millisekunden seit dem letzten Funktionsaufruf nach oben
const long interval = 60000; //60000 Millisekunden aka 60 Sekunden, das Interval wie oft der Sensor überhaupt benutzt wird
void setup()
{
client.setServer(server, 1883);
client.setCallback(callback);
Ethernet.begin(mac, ip);
delay(1500);
lastReconnectAttempt = 0;
Serial.begin(9600);
Serial.println("MQTT - Test!");
sensor.begin();
pinMode(bewegung, INPUT);
}
void loop()
{
if (!client.connected()) {
long now = millis();
if (now - lastReconnectAttempt > 5000) {
lastReconnectAttempt = now;
// Attempt to reconnect
if (reconnect()) {
lastReconnectAttempt = 0;
}
}
} else {
// Client connected
client.loop();
}
unsigned long currentMillis = millis();
//Si7021 Temperature & Humidity
if (currentMillis - previousMillis7021 >= interval) {
previousMillis7021 = currentMillis;
h = sensor.readHumidity(); //Luftfeuchte auslesen
t = sensor.readTemperature(); //Temperatur auslesen
}
// Prüfen ob eine gültige Zahl zurückgegeben wird. Wenn NaN (not a number) zurückgegeben wird, dann Fehler ausgeben.
if (isnan(t) || isnan(h))
{
Serial.println("Si7021 konnte nicht ausgelesen werden");
client.publish("fhem/universalsensor/Arduino","Sensorfehler",true); //true sendet die Nachricht retained, d.h. die Nachricht bleibt solange auf dem Broker, bis etwas neues kommt
}
else if (h == h_alt && t == t_alt)
{
//nix machen
}
else
{
client.publish("fhem/universalsensor/Arduino","online", true);
dtostrf(h,6, 1, humidity);
dtostrf(t,6, 1, temperature);
client.publish("fhem/universalsensor/Humidity",humidity, true);
client.publish("fhem/universalsensor/Temperature",temperature, true);
h_alt = h; //den alten Messwert aufheben
t_alt = t; //um nur bei Veränderung zu reagieren
Serial.print("Luftfeuchte: ");
Serial.print(h);
Serial.print(" %\t");
Serial.print("Temperatur: ");
Serial.print(t);
Serial.println(" C");
}
// PIR
if (currentMillis - previousMillisPIR >= 2000) {
bewegungsstatus=digitalRead(bewegung);
previousMillisPIR = currentMillis;
Serial.print("Bewegung:");
if (bewegungsstatus == HIGH)
{
client.publish("fhem/universalsensor/bewegung","on", true);
Serial.println("on");
}
else
{
client.publish("fhem/universalsensor/bewegung","off", true);
Serial.println("off");
}
}
}
Leider kommt in FHEM nicht an und mit MQTT.fx empfange ich auch nichts.
Sieht wer den Fehler? :-[
Mfg
Philipp
Was sagt denn die serielle Ausgabe?
Die sollte ja hinreichend gesprächig sein.
Zitat von: Rince am 11 April 2017, 21:23:44
Was sagt denn die serielle Ausgabe?
Die sollte ja hinreichend gesprächig sein.
Die serielle Ausgabe sagt nicht sehr viel...
Nach einem
MQTT - Test! kommt nur noch ob eine Bewegeung erkannt wurde, oder nicht.
Meinem Arduino habe ich die IP
192.168.0.121 gegeben, welche sich auch anpingen lässt.
Und in MQTTfx steht, dass insgesamt 2 Clients mit dem Broker verbunden sind, aber eigentlich müssten es doch drei sein?
1. Computer mit MQTTfx
2. Arduino
3. FHEM
Was ist denn an meinem Code falsch? :-[
Tu doch mal nur so einen MQTT Beispielsketch drauf (IP und Broker IP anpassen).
Zitat von: Rince am 13 April 2017, 09:04:48
Tu doch mal nur so einen MQTT Beispielsketch drauf (IP und Broker IP anpassen).
Ich habe jetzt mal diesen Sketch auf den Arduino hochgeladen:
/*
Basic MQTT example
This sketch demonstrates the basic capabilities of the library.
It connects to an MQTT server then:
- publishes "hello world" to the topic "outTopic"
- subscribes to the topic "inTopic", printing out any messages
it receives. NB - it assumes the received payloads are strings not binary
It will reconnect to the server if the connection is lost using a blocking
reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
achieve the same result without blocking the main loop.
*/
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(172, 16, 0, 100);
IPAddress server(172, 16, 0, 2);
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i=0;i<length;i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
EthernetClient ethClient;
PubSubClient client(ethClient);
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("ArduinoMEGA")) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("outTopic","hello world");
// ... and resubscribe
client.subscribe("inTopic");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup()
{
Serial.begin(57600);
client.setServer(server, 1883);
client.setCallback(callback);
Ethernet.begin(mac, ip);
// Allow the hardware to sort itself out
delay(1500);
}
void loop()
{
if (!client.connected()) {
reconnect();
}
client.loop();
client.publish("zuHause/ArduinoMEGA","online", true);
}
In MQTTfx steht und BrokerStatus auch, dass immer mehr Nachrichten eintreffen, aber wenn ich
zuHause/ArduinoMEGA subscribe stehen dort keine Nachrichten.
Gibt es eine Möglichkeit, mit der ich alle Nachrichten sehen kann?
Mfg
Philipp
Subscribe auf #. Dann siehst du alles. Guck mal auch in die Mqtt FAQ ;)