Ankündigung

Einklappen
Keine Ankündigung bisher.

Lesen der Uhrzeit DPT 10.001

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Lesen der Uhrzeit DPT 10.001

    Hallo zusammen,

    ich habe ein Problem mit dem Einlesen der über den KNX Bus bereitgestellten Uhrzeit.

    Ich hatte ein Beispiel gefunden, in dem das Struct tm (https://cplusplus.com/reference/ctime/tm/) verwendet wird.

    voidcallbackTime(GroupObject&go) {
    structtmrxdTime;
    bool success = false;

    rxdTime = go.value();
    tmp_sec = rxdTime.tm_sec;
    tmp_min = rxdTime.tm_min;
    tmp_hour = rxdTime.tm_hour;
    tmp_wday = (rxdTime.tm_hour & dayMask) >> 5;
    ....

    Das Ergebnis ist allerdings immer 0 für sec, min, hour.

    Ich verwende das "gleiche" für das Datum und das funktioniert.

    oidcallbackDate(GroupObject&go) {
    structtmmyTime;
    bool success = false;
    myTime = go.value();
    tmp_mday = myTime.tm_mday;
    tmp_month = myTime.tm_mon;
    tmp_year = myTime.tm_year;


    Ich verstehe allerdings auch nicht, wie das Struct tm zu DPT 10.001 und DPT11.001 passt.

    Kann mir hier jemand ein Beispiel für DPT 10.001 geben?

    Danke und Gruß
    Helmut

    #2
    Hi Helmut,

    das ist prinzipiell schon richtig so. Dir ist aber klar, dass es 2 verschiedene KO sind (und damit auch 2 verschiedene callbacks), die das angesprochen werden?

    Gruß, Waldemar

    Kommentar


      #3
      Hallo Waldemar,

      ja ich habe 2 unterschiedliche Callbacks. Ich sehe das Problem in der Struct tm. Die enthält alles Time und Date. KNX liefert aber nur 3 Byte und ich kann mir nicht vorstellen, dass der KNX Stack das dann richtig im Struct tm ablegt.

      Ich habe auch schon versucht 2 eigene Struct aufzumachen, die aus meiner Sicht die 3 KNX Bytes abdecken, das lässt sich dann aber nicht kompilieren.
      // DPT 10.001
      structknxTime {
      uint8_t seconds;
      uint8_t minutes;
      uint8_t hours;
      };

      // DPT 11.001 masks
      constuint8_t dayOfMonthMask = 0x1F;
      constuint8_t monthMask = 0x0F;
      constuint8_t yearMask = 0x7F;
      String dayString = "";
      // DPT 11.001
      structknxDate {
      uint8_t year;
      uint8_t month;
      uint8_t day;
      };



      //--------------------------------------------------------------
      voidcallbackDate(GroupObject&go) {
      structknxDatemyTime;
      bool success = false;
      int objectSize = 0;
      objectSize = go.valueSize();
      DEBUG_VERBOSE("callbackDate(%d): >>>>>>>>>> new KNX Date event received - objectSize = %d", loopCntr, objectSize);
      myTime = go.value();
      tmp_mday = myTime.tm_mday;
      tmp_month = myTime.tm_mon;
      tmp_year = myTime.tm_year;
      shortunsignedint subYear = tmp_year - 2000;
      DEBUG_VERBOSE("callbackDate(%d-0): >>>>>>>>>> new KNX Date event received - tmp_mday = %d; tmp_month = %d; subYear = %d", loopCntr, tmp_mday, tmp_month, subYear);
      currentDate = dayString + String(tmp_mday) + "." + String(tmp_month) + "." + String(subYear);
      DEBUG_VERBOSE("callbackDate(%d-1) new KNX DATE event received - %s", loopCntr, String(currentDate).c_str());
      #ifdef LCD
      writeLcdDate(currentDate);
      #endif
      // set job to update display
      success = jobQueue.enchain(TRIGGER_DISPLAY);
      DEBUG_VERBOSE("callbackDate(%d-2) - jobQueue - TRIGGER_DISPLAY: Job = %d\n", loopCntr, TRIGGER_DISPLAY);
      if (!success) {
      DEBUG_ERROR("callbackDate(%d-3) - jobQueue - TRIGGER_DISPLAY: ##### writing jobQueue failed!!! #####\n", loopCntr);
      }
      }

      //--------------------------------------------------------------
      voidcallbackTime(GroupObject&go) {
      structknxTimerxdTime;
      bool success = false;

      int objectSize = 0;
      objectSize = go.valueSize();
      DEBUG_VERBOSE("callbackTime(%d): >>>>>>>>>> new KNX TIME event received - objectSize = %d", loopCntr, objectSize);

      rxdTime = go.value();
      tmp_sec = rxdTime.tm_sec;
      tmp_min = rxdTime.tm_min;
      tmp_hour = rxdTime.tm_hour;
      tmp_wday = (rxdTime.tm_hour & dayMask) >> 5;
      DEBUG_VERBOSE("callbackTime(%d-0): >>>>>>>>>> new KNX TIME event received - tmp_wday = %d; tmp_min = %d; tmp_hour = %d; ", loopCntr, tmp_wday, tmp_min, tmp_hour);
      buildDayStr(tmp_wday);
      currentTime = String(tmp_hour) + ":" + String(tmp_min);
      DEBUG_VERBOSE("callbackTime(%d-1): new KNX TIME event received - %s", loopCntr, String(currentTime).c_str());
      #ifdef LCD
      writeLcdTime(currentTime);
      #endif
      ...


      Das endet dann immer in
      In file included from /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/openknx_taster_monochromes_display_sensoren.ino:26 2:
      /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/knx_events.h: In function 'void callbackDate(GroupObject&)':
      /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/knx_events.h:32:21: error: no match for 'operator=' (operand types are 'knxDate' and 'KNXValue')
      32 | myTime = go.value();
      | ^
      In file included from /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/openknx_taster_monochromes_display_sensoren.ino:18 9:
      /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/config.h:270:8: note: candidate: 'knxDate& knxDate:perator=(const knxDate&)'
      270 | struct knxDate {
      | ^~~~~~~
      /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/config.h:270:8: note: no known conversion for argument 1 from 'KNXValue' to 'const knxDate&'
      /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/config.h:270:8: note: candidate: 'knxDate& knxDate:perator=(knxDate&&)'
      /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/config.h:270:8: note: no known conversion for argument 1 from 'KNXValue' to 'knxDate&&'
      In file included from /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/openknx_taster_monochromes_display_sensoren.ino:26 2:
      /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/knx_events.h:33:21: error: 'struct knxDate' has no member named 'tm_mday'
      33 | tmp_mday = myTime.tm_mday;
      | ^~~~~~~
      /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/knx_events.h:34:22: error: 'struct knxDate' has no member named 'tm_mon'
      34 | tmp_month = myTime.tm_mon;
      | ^~~~~~
      /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/knx_events.h:35:21: error: 'struct knxDate' has no member named 'tm_year'; did you mean 'year'?
      35 | tmp_year = myTime.tm_year;
      | ^~~~~~~
      | year
      In file included from /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/openknx_taster_monochromes_display_sensoren.ino:26 2:
      /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/knx_events.h: In function 'void callbackTime(GroupObject&)':
      /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/knx_events.h:67:22: error: no match for 'operator=' (operand types are 'knxTime' and 'KNXValue')
      67 | rxdTime = go.value();
      | ^
      In file included from /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/openknx_taster_monochromes_display_sensoren.ino:18 9:
      /Users/helric/Projekte/openKNX/openknx_taster_monochromes_display_sensoren/config.h:255:8: note: candidate: 'knxTime& knxTimeperator=(const knxTime&)'
      255 | struct knxTime {
      ...
      Ich bin im C-Bereich nur Anfänger und steh hier vor einem Scheunentor ...

      Gruß
      Helmut

      Kommentar


        #4
        Workaround:
        als bytearray lesen und selber parsen...

        Kommentar


          #5
          Parsen ist kein Problem, aber wie bekomme ich die 3 Byte Payload in ein Byte Array? Hier setzen meine C-Kenntnisse aus.
          Könntest du mir da ein Code-Beispiel geben?

          Danke und Gruß
          Helmut

          Kommentar


            #6

            Zitat von Ing-Dom Beitrag anzeigen
            als bytearray lesen und selber parsen...
            Nö, besser nachgucken, was genau beim Empfang vom Telegramm am KO passiert.

            Zitat von mobil750 Beitrag anzeigen
            KNX liefert aber nur 3 Byte und ich kann mir nicht vorstellen, dass der KNX Stack das dann richtig im Struct tm ablegt.
            Du hast doch die Sourcen, schau doch einfach nach:
            Code:
            int busValueToTime(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
            {
                ASSERT_PAYLOAD(3);
                switch (datatype.index)
                {
                    case 0:
                        value = (uint8_t)((unsigned8FromPayload(payload, 0) >> 5) & 0x07);
                        return true;
                    case 1:
                    {
                        unsigned char hours = unsigned8FromPayload(payload, 0) & 0x1F;
                        unsigned char minutes = unsigned8FromPayload(payload, 1) & 0x3F;
                        unsigned char seconds = unsigned8FromPayload(payload, 2) & 0x3F;
                        if (hours > 23 || minutes > 59 || seconds > 59)
                            return false;
                        struct tm tmp = {0};
                        tmp.tm_hour = hours;
                        tmp.tm_min = minutes;
                        tmp.tm_sec = seconds;
                        value = tmp;
                        return true;
                    }
                }
                return false;
            }
            ​
            Da sieht man dann, dass man ein Time-value mit Dpt(10,1,1) abholen muss. Du hast wahrscheinlich Dpt(10,1,0) genommen.

            Gruß, Waldemar

            P.S.: Bitte Coding in Zukunft mit dem   [CODE] -Tag einbetten, nicht über quote, das kann man nicht lesen.

            Kommentar


              #7
              Hallo Waldemar,

              danke für die ausführliche Antwort. Allerdings geht das schon extrem tief in den Stack, wobei mir unklar ist wie da der Aufruf erfolgt.

              Im Prinzip müssten doch diese Details für die Anwendung transparent sein, so wie es auch bei allen anderen DPTs ist.

              Hier meine Code-Schnipsel für Date (funktioniert) und Time (funktioniert nicht).

              Code:
              #define grpObjDate knx.getGroupObject(COMOBJ_Datum)
              #define grpObjTime knx.getGroupObject(COMOBJ_Zeit)
              
                grpObjDate.callback(callbackDate);
                grpObjDate.dataPointType(DPT_Date);
              
                grpObjTime.callback(callbackTime);
                grpObjTime.dataPointType(DPT_TimeOfDay);
              
              
              ​//--------------------------------------------------------------
              void callbackDate(GroupObject& go) {
                struct tm myTime;
                bool success = false;
              
                myTime = go.value();
                tmp_mday = myTime.tm_mday;
                tmp_month = myTime.tm_mon;
                tmp_year = myTime.tm_year;
                short unsigned int subYear = tmp_year - 2000;
              
                DEBUG_VERBOSE("callbackDate(%d-0): >>>>>>>>>> new KNX Date event received - tmp_mday = %d; tmp_month = %d; subYear = %d", loopCntr, tmp_mday, tmp_month, subYear);
              .....
              
              
              ​//--------------------------------------------------------------
              void callbackTime(GroupObject& go) {
                struct tm rxdTime;
                bool success = false;
              
                rxdTime = go.value();
              ​//  rxdTime = go.value(DPT_TimeOfDay);     -> bringt auch nichts
              
                tmp_min = rxdTime.tm_min;
                tmp_hour = rxdTime.tm_hour;
                tmp_wday = (rxdTime.tm_hour & dayMask) >> 5;
              
                DEBUG_VERBOSE("callbackTime(%d-0): >>>>>>>>>> new KNX TIME event received - tmp_wday = %d; tmp_hour = %d; tmp_min = %d", loopCntr, tmp_wday, tmp_hour, tmp_min);
              .....
              ​
              ​
              ​
              Wie man aus deinem zitierten Code-Auszug auch sieht fehlt da ein für mich relevanter Wert, der dayOfWeek, den ich gerne anzeigen möchte.
              Klar den kann ich mir den in den Sourcen selbst nachbauen, oder eben das Maskieren von tm_hour entfernen.

              Entweder habe ich da noch einen Fehler in meinem Code, den ich nicht erkenne, oder da stimmt im Stack was nicht. Liege ich da richtig?

              Für mich wäre es in diesem Fall auch völlig ausreichend die 3 Byte direkt auszulesen, nur dazu fehlen mir allerdings die Coding Skills. Es hapert da am Verständnis der notwendigen Typ-Definitionen / Umwandlung ...
              Ein Beispiel für das Abholen der 3 Bytes wäre super.

              Danke und Gruß
              Helmut

              Kommentar


                #8
                Zitat von mobil750 Beitrag anzeigen
                Entweder habe ich da noch einen Fehler in meinem Code, den ich nicht erkenne, oder da stimmt im Stack was nicht. Liege ich da richtig?
                Der stack ist nicht ideal bei der conversion der Datentypen. Da könnte man verbessern, da haben wir auch schon diskutiert. Hat halt aktuell nicht die oberste Prio.
                Speziell mit Uhrzeit hatte sich aber auch schon Cornelius intensiver beschäftigt, Status kenne ich aber nicht...

                Grundsätzlich gilt: wenn du was am stack verbessert haben willst, mache es. PRs welcome.

                Kommentar


                  #9
                  Hi Helmut,

                  ich gebe gerne Hilfe zur Selbsthilfe, in der annahme, dass man sich in das Thema eindenkt und motiviert ist, eigene Probleme zu lösen und daraus zu lernen.

                  Zitat von mobil750 Beitrag anzeigen
                  Hier meine Code-Schnipsel für Date (funktioniert) und Time (funktioniert nicht).
                  Mit der Aussage weißt Du, dass Time nicht geht.

                  Zitat von mumpf Beitrag anzeigen
                  Da sieht man dann, dass man ein Time-value mit Dpt(10,1,1) abholen muss. Du hast wahrscheinlich Dpt(10,1,0) genommen.
                  Oben sage ich, dass Du wahrscheinlich auf Time mit dem falschen Dpt zugreifst.

                  Zitat von mobil750 Beitrag anzeigen
                  grpObjTime.dataPointType(DPT_TimeOfDay);
                  Dein Codeschnipsel sagt, dass Du mit DPT_TimeOfDay zugreifst.

                  Nachschauen im Header-File:
                  Code:
                  #define DPT_TimeOfDay Dpt(10, 1)
                  Ok, ist weder Dpt(10,1,0) noch Dpt(10,1,1).

                  Im Kostruktor nachgeschaut:
                  Code:
                  Dpt::Dpt(short mainGroup, short subGroup, short index /* = 0 */)
                  Aha, Dpt(10,1) entspricht Dpt(10,1,0).

                  Ausprobieren:
                  Du änderst Dein Coding in
                  Code:
                  grpObjTime.dataPointType(Dpt(10,1,1));
                  Ok, funktioniert. Jetzt kann man aufhören. Oder den Community-Gedanken weiterverfolgen und das Headerfile ändern:
                  Code:
                  #define DPT_TimeOfDay Dpt(10, 1, 1)
                  ​Danach einen Pull-Request erstellen mit dem Hinweis, dass man einen Fehler im Stack gefunden hat und TimeOfDay für den Gelegenheitsuser eher so definiert sein sollte.

                  Zitat von mobil750 Beitrag anzeigen
                  Allerdings geht das schon extrem tief in den Stack, wobei mir unklar ist wie da der Aufruf erfolgt.
                  Ich weiß auch nicht, wie der Aufruf erfolgt. Das ist auch nicht wichtig. Irgendwann muss eine payload im Telegramm in Abhängigkeit vom DPT in einen Wert gewandelt werden und da passiert es. Zum nachschauen reicht das.

                  Zitat von mobil750 Beitrag anzeigen
                  Im Prinzip müssten doch diese Details für die Anwendung transparent sein, so wie es auch bei allen anderen DPTs ist.
                  Das ist eine Erwartungshaltung, die man (vielleicht) an einen professionellen Stack stellen kann (und selbst da dürfte es nicht immer so sein). Auch stimmt es nicht, dass das Verhalten bei zusammengesetzten DPT immer nach oben transparent sein kann, es hängt davon ab, was man bezweckt.

                  Ich will hier nicht kritisieren, sondern die Erwartungshaltung zurechtrücken. Es ist vieles nicht perfekt und Verbesserungen sind willkommen. Allerdings können diese nicht von uns vorgenommen werden sondern müssen auch von der Community kommen. Schon bei ganz wenig nutzern ist es unmöglich zu realisieren, wenn jeder sagt "mach es besser" und nur einer es machen soll.

                  Ich hoffe, Du bekommst Deine Lösung jetzt hin, wenn nicht, helfe ich gerne weiter.
                  Gruß, Waldemar

                  Kommentar


                    #10
                    Hallo Waldemar,

                    danke für die Erläuterungen.

                    Ich habe deine Vorschläge ausprobiert. Nur​ wenn man die dpt.h entsprechend deiner Beschreibung ergänzt, funktioniert der DPT 10.001 korrekt.

                    Da mir dann noch der Wochentag fehlt, habe ich die entsprechende Erweiterung in der dptconvert.cpp durchgeführt. Mein Problem ist damit gelöst.

                    Die beiden Änderungen habe ich dann auch, wie von dir vorgeschlagen, als Pull-Request eingestellt.

                    Das war heute sehr lehrreich! Bleibt nur noch die Frage, wie ich dieses Topic als gelöst markieren kann ...

                    Gruß
                    Helmut

                    Kommentar


                      #11
                      Setze einfach bei dem passenden Beitrag den Haken rechts unten
                      IMG_8321.jpg
                      Gruß Bernhard

                      Kommentar


                        #12
                        Hallo Bernhard,

                        bei keinem der Beiträge gibt es die Möglichkeit den Haken zu setzen ....
                        Bildschirmfoto 2023-04-01 um 18.46.47.png
                        Muss man das irgendwo konfigurieren?

                        Gruß
                        Helmut

                        Kommentar


                          #13
                          Eigentlich nicht und da Du den Thread erstellt hast, sollte das gehen. Aber egal, kannst Du auch einfach so lassen, ging früher vor dem Update der Forensoftware (das diese Funktion einführte) ja auch.

                          Also alles gut.
                          Gruß Bernhard

                          Kommentar


                            #14
                            Ich hatte vor einigen Tagen das gleiche Problem und hier dokumentiert wie's zu lösen ist:
                            knx/issues/233

                            Edit: Lösung war ja schon weiter oben...

                            Kommentar

                            Lädt...
                            X