Wetterstation mit RS485

Hallo Kollegen,
ich bin noch recht unerfahren was das Programmieren angeht. Daher die Frage an euch.
Ich habe eine Wetterstation (Elsner P03/3-RS485-GPS) mit RS485, die ich mit dem Arduino auslesen möchte.
Die Station sendet permanent 61 Bytes an Daten im ASCII Format. Wobei ich aber nur die Bytes 2-6 und 17-21 weiterverarbeiten möchte. Das Byte 61 enthält als Endkennung 0x03.
Ist es möglich die Daten in ein Array zu speichern und nur die oben genanten Bytes wieder auszulesen?
Wäre prima wenn ihr mir da etwas auf die Sprünge helfen könntet.

MfG Erwin

Im englischen Teil des Forum müssen die Beiträge und Diskussionen in englischer Sprache verfasst werden. Deswegen wurde diese Diskussion in den deutschen Teil des Forums verschoben.

mfg ein Moderator.

Ja. bei 61 bytes kein Ding.

char empfangsdaten[] = {"ABCDEFGNIJKLMNOPQRSTUVWXYZ"};
void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  for (byte b = 1; b <= 5; b++)
  {
    Serial.print(empfangsdaten[b]);
    Serial.print(" ");
  }
  Serial.println();
  for (byte b = 16; b <= 20; b++)
  {
    Serial.print(empfangsdaten[b]);
    Serial.print(" ");
  }
  Serial.println();
}

void loop()
{
}

Hallo
Gibt es zur der Wetterstation-Schnittstelle eine Beschreibung und was noch besser wäre ein Datalogging?
Welcher Arduino wird eingesetzt?
Ich wünsche einen geschmeidigen Tag und viel Spass beim Programmieren in C++.

es gibt das Tutorial
"Serial Input Basic"

https://forum.arduino.cc/t/serial-input-basics-updated/382007

das beschreibt gut wie du verlässlich Daten empfangen kannst.

Wenn du dann die Daten in einem Char array hast, soll es ein Leichtes sein, nur bestimmte Stellen zu extrahieren.

Protokoll ist eh schön beschrieben:
https://www.elsner-elektronik.de/shop/de/fileuploader/download/download/?d=1&file=custom%2Fupload%2F30140_P033-RS485basic_Datenblatt_07Jun21_DBEEA6044.pdf

Ich hab Dir mal was gebaut.
Der liest auf Serial1 ein.
Wenn Du SoftwareSerial machst, dann die 3 Zeilen ändern.
Du brauchst nicht auf die EndeKennung warten, da die Übertragung mit G anfängt.
Na dann...

uint8_t position = 0;
bool start = false;
char temp[6] = {0};
char wind[5] = {0};
void setup()
{
  Serial.begin(115200);
  Serial1.begin(19200); // Vorgabe Wetterstation
  Serial.println(F("Start..."));
}

void loop()
{
  if (Serial1.available() > 0)
  {
    char zeichen = Serial1.read();
    //Serial.println(zeichen);
    if (zeichen == 'G')                             // StartKennung
    {
      Serial.println("Start erkannt");
      start = true; position = 0;
      memset(wind, sizeof(wind), 0);
      memset(temp, sizeof(temp), 0);
    }
    else if (start)
    {
      if (position > 0 && position < 6)           // Temp: -99.9
      {
        temp[position - 1] = zeichen;
      }
      if (position > 15  && position < 20)       // wind: 99.9
        wind[position - 16] = zeichen;
      if (position > 20)
      {
        start = false;
        Serial.println(temp);
        Serial.println(wind);
      }
    }
    position++;
  }
}

Wen die wirklich nach Norm arbeiten dan darfst Du das nicht direkt auf Arduino anschlissen, Du braust dafür ein "Konverter"

Das ging ja Fix.
Vielen lieben Dank Leute, ich werde das heute Abend gleich mal ausprobieren.
MfG Erwin

Machen se... :wink:

Ich gehe davon aus, das Du nen MAX485 da noch am laufen hast - siehe @fony - denn das Signal kommt als Differenzsignal mit dem 24V Pegel. Da gibt es Rauch...

Ja natürlich.

Noch was RS485 braucht keinen gemeinsamen GND reicht nur A und B,
es wird heufig falsch behauptet das man braucht auch an der anschlussiete drite Ader

Ist mir bekannt. Aber trotzdem Danke für die Info :wink:

meine Proof of Concept schaut ca so aus:

/*
   Weatherstation Elsner P03/3-RS485 GPS
   https://forum.arduino.cc/t/wetterstation-mit-rs485/943408/5   Started with Example 4 https://forum.arduino.cc/t/serial-input-basics-updated/382007/3

   https://www.elsner-elektronik.de/shop/de/fileuploader/download/download/?d=1&file=custom%2Fupload%2F30140_P033-RS485basic_Datenblatt_07Jun21_DBEEA6044.pdf
   message examples
   W+23.4123456J99912.3J99999999999999999           (remember: send 0x03 as end marker!)

   by noiasca
   2021-01-05
*/

struct Data
{
  float temperatureOut; //AT
  float sunSouth;       // SoS  Sonne Süd
  float sunWest;        // Sonne West
  float sunEast;        // Soo - Sonne Ost
  bool dusk;           // Dämmerung
  float brightness;
  float wind;
  bool rain;
  uint16_t checksum;
};

class Weatherstation {
    static const byte numChars = 64;  // receiver buffer size
    char receivedChars[numChars];     // an array to store the received data
    boolean newData = false;
    Stream &stream;
    void (*cbOnNewData)();            // gets called after we received a full message

  public:
    Data data;                        // MISSING: make protected and provide get functions

    Weatherstation (Stream &stream) : stream(stream) {}

    void setOnNewData(void (*cbOnNewData)())
    {
      (*this).cbOnNewData = cbOnNewData;
    }

    void delBuffer()
    {
      memcpy(receivedChars, "", numChars);
    }

    void update()          // was recvWithEndMarker();
    {
      static byte ndx = 0;
      char endMarker = 0x03;
      char rc;
      if (stream.available() > 0) {
        rc = stream.read();
        if (rc != endMarker) {
          //if (rc == 'W' || rc == 'G') // wtf .. W kommt auch im Payload vor ... daher mal auskommentiert
         // {
         //  delBuffer(); // force begin of telegram
         //   ndx = 0;
         // }
          receivedChars[ndx] = rc;
          ndx++;
          if (ndx >= numChars) {
            ndx = numChars - 1;
          }
        }
        else {
          receivedChars[ndx] = '\0'; // terminate the string
          ndx = 0;
          newData = true;
          parseLine();
        }
      }
    }

    void parseLine() {
      if (newData == true) {
        // output all
        //Serial.print(F("This just in ... ")); Serial.println(receivedChars);
        //int success = -1;
        // MISSING: validate checksum
        // parase data
        // W start marker
        // +/- set later
        data.temperatureOut = (receivedChars[2] - '0') * 10;
        data.temperatureOut += (receivedChars[3] - '0');
        // .
        data.temperatureOut += (receivedChars[5] - '0') / 10.0;
        if (receivedChars[1] == '-')  data.temperatureOut = data.temperatureOut * -1;
        data.sunSouth = (receivedChars[6] - '0') * 10;
        data.sunSouth += (receivedChars[7] - '0');
        data.sunWest = (receivedChars[8] - '0') * 10;
        data.sunWest += (receivedChars[9] - '0');
        data.sunEast = (receivedChars[10] - '0') * 10;
        data.sunEast += (receivedChars[11] - '0');
        if (receivedChars[12] == 'J') data.dusk = true; else data.dusk = false;
        data.brightness = (receivedChars[13] - '0') * 100;
        data.brightness += (receivedChars[14] - '0') * 10;
        data.brightness += (receivedChars[15] - '0');
        data.wind = (receivedChars[16] - '0') * 10;
        data.wind += (receivedChars[17] - '0');
        // . not needed
        data.wind += (receivedChars[19] - '0') / 10.0;
        if (receivedChars[20] == 'J') data.rain = true; else data.rain = false;
        if (cbOnNewData) cbOnNewData();
        newData = false;
      }
    }
};

//#include <AltSoftSerial.h>
//#define RX_PIN 8
//#define TX_PIN 9
//AltSoftSerial altSerial;
//Weatherstation weatherstation(altSerial);    // receive data from Smartmeter with altSerial

Weatherstation weatherstation(Serial);         // debugging with HW Serial

// user sketch specific variables and functions

// this function will be called each time we have received a new packet (=several lines)
void callbackOnNewData()
{
  printAllData();
}

void printAllData() // quick'n'dirty print
{
  Serial.print(F("temperatureOut ")); Serial.println(weatherstation.data.temperatureOut);
  Serial.print(F("wind           ")); Serial.println(weatherstation.data.wind);
}

// Arduino setup and loop
void setup() {
  Serial.begin(115200);  // local debug output
  //altSerial.begin(19200);

  weatherstation.setOnNewData(callbackOnNewData); // register a callback onNewData
  weatherstation.delBuffer();
}

void loop() {
  weatherstation.update();
}

sind neue Daten da, wird das callback angestoßen.
Darin kann man auch noch andere Sachen machen.

wenn du uns ein paar Mustertelegramme postest, kann man das mit der Checksumme auch noch ergänzen...

Vielen Dank, bin leider jetzt erst dazugekommen.
Sieht sehr interessant aus. Muss mich aber erstmal in ruhe damit auseinander setzen, da ich aktuell nur die hälfte des Codes kapier. :laughing:

wenn du das oben verlinkte Serial Input Basics Tutorial durch gemacht hast dann verstehst du auch leichter was in meinem Code passiert. Es ist nämlich genau das Beispiel 4 nur eben als Klasse.

Und mein Angebot steht: wenn du ein paar echte Telegramme postest dann mach ich die Prüfziffernrechnung auch noch. Aber ohne Musterdaten kann ich die Fehlerfreiheit nicht feststellen und dann fang ich erst gar nicht an.

Warum nicht?
Das Format und die Inhalte sind bekannt.
Im übrigen ist das verlinkte Datenblatt nicht das, was der TO hat; :wink: Inhaltlich geht es da noch weiter.... https://www.elsner-elektronik.de/shop/de/fileuploader/download/download/?d=1&file=custom%2Fupload%2F30145_30151_P033-RS485-GPS_CET_Datenblatt_07Jun21_DBEEA6143.pdf

weil ich nicht Zeit in die Generierung von Testdaten investiere die der Threadowner einfach posten könnte.

So, ich habe jetzt 3 Klassen daraus gemacht für jede Station eine eigene.
Wers lesen mag: http://werner.rothschopf.net/microcontroller/202112_elsner_weatherstation_p03_basic_cet_GPS_en.htm

Was mich von @erwin82 auch noch interessieren würde, wie sich der Sensor bei direkter Sonnenbestrahlung verhält, kann das Ding dann wirklich noch eine unverfälschte Außentemperatur ermitteln?

Hallo noiasca,
der Temperatursensor ist unterhalb der Wetterstation angebracht, deswegen denk ich das direkte Sonneneinstrahlung nicht ganz so sehr die Messung verfälscht.
Ich hab mal ein Screenshot vom Seriellen Monitor gemacht.