.....welche Variable kann ich nehmen?

Moin,

ich lese ein JSON aus, in dem folgender Inhalt hinterlegt ist:

{"version":"0.3","data":{"tuples":[[1512577066206,7.812,1]],"uuid":"xxxxxxxx-xxx-1xxx-xxx-xxxxxxxxxx","from":1512577019674,"to":1512577066206,"min":[1512577066206,7.812],"max":[1512577066206,7.812],"average":7.812,"rows":2}}

Die "7.812" ist eine Temperatur. Die kann ich in eine 'float' Variable speichern. Kein Problem!
Die "1512577066206" ist ein MySQL Timestamp.
.....in was für eine Variable kann ich den speichern?
(zu lang für int, long, uint32_t)
(uint64_t scheint auf einem ESP8266 nicht zu funktionieren und ich kann das auch nicht mit Serial.print benutzen)
Deswegen würde ich das einfach als Zeichenkette / String / Char haben wollen. (Ist das alles das gleiche oder sind das verschiede Sachen?)

Aber irgendwie gelingt mir das nicht, oder ich hab irgendwo ein anderes Problem (was ich nicht verstehe).

Das Array 'Temperatur' ist folgendermaßen deklariert:
float Temperatur[8]={0};
Diese Übernahme funktioniert:
Temperatur[1] = data_tuples0[1]; // data_tuples0[1] ist eine Adresse in dem JSON. Das funktioniert!
Die Ausgabe funktioniert:
Serial.print(Temperatur[1]);

Die Variable 'zwischen' ist folgendermaßen deklariert:
char zwischen;
Ob die Übernahme funktioniert weiss ich nicht:
zwischen = data_tuples0[0]; // 'data_tuples0[0]' ist eine Adresse in dem JSON. Das funktioniert!
Die Ausgabe
Serial.println(zwischen);
Fördert leider nur ein "⸮" zu Tage :frowning:

Was ist das Problem und wie löse ich es?

Lieben Dank und lieben Gruß,
Chris

P.S. Natürlich könnt ihr den ganzen Code haben, aber der ist 500 Zeilen lang, den liest sich sowieso keiner ganz durch, braucht man auch nicht, und bringt euch trotzdem keine andere Erkenntnis, jedenfalls ist das meine Erfahrung aus mehreren anderen Threads.

Wie ich letztens in einer anderen Diskussion lernen durfte ist der MySQL-Timestamp der UNIX-Timestamp in Millisekunden (also x 1000). Der passt in eine uint64_t. Ein Print ist dafür nicht vorgesehen. Da kannst Du aber immer noch /1000 in einen uint32_t setzen und den printen.
Probier mal, ob der unt64_t % 1000 den Rest richtig bringt, dann kannst Du Dir eine eigene Printfunktion bauen.

String und char ist natürlich nicht das Gleiche. Schau Dir zum Verständnis mal Zeichenketten in C an.

Gruß Tommy

uint64_t funktioniert auf dem ESP8266 prima.

uint64_t ull=1512577066206ULL;


void printUll(uint64_t zahlUll) {
  uint32_t ul = zahlUll / 1000;
  uint16_t ui = zahlUll % 1000;
  Serial.print(ul);Serial.println(ui);
}

void setup() {
  Serial.begin(115200);
  printUll(ull);
}

Ist nur erst mal ein Schnellschuss zum Testen. Man könnte den Stream noch mit rein geben.

Gruß Tommy

Müsste auf dem ESP nicht auch ein long 64 Bit haben?

In der Arduino-IDE nicht (gerade getestet). Das hat wohl Kompatibilitätsgründe.

Gruß Tommy

Gut zu wissen. Wäre irgendwie naheliegend gewesen.

Vor allem da ein (nicht unsigned) int i=65000 auch als 65000 geprintet wird.
Irgendwie ist das auf dem ESP8266 in sich unlogisch.

Gruß Tommy

Edit: Man sollte also auf dem ESP8266 unbedingt die uintx_t - Schreibweise nutzen, um sicher zu sein, was man für eine Länge hat.

Edit2: Gerade getestet - der ESP32 verhält sich genau so.

Pass bei unit auf, wenn Du sie an einen AVR-Arduino übertragen willst. Da musst Du pack verwenden, da der Compiler auf dem ESP an 32Bit-Grenzen ausrichtet, bei AVR an 8Bit-Grenzen.

Da wird #pragma pack wichtig.

Wir haben das hier ausgetestet.

Ich habe es auch hier angewendet.

Gruß Tommy

Auf 32/64 Bit Prozessoren ist long und int i.d.R. das Gleiche. Das ist normal. 64 Bit ist long long

aber so ganz konsistent ist die Bezeichnung nicht. Ich werde also lieber die uintx_t bzw intx_t nehmen, da weiß man, was man hat :wink:

Gruß Tommy

Wie ich letztens in einer anderen Diskussion lernen durfte ist der MySQL-Timestamp der UNIX-Timestamp in Millisekunden (also x 1000).

Ja, das waren auch wir beide :slight_smile:
Jetzt hab ich endlich mal wieder n paar Minuten Zeit um damit mal weiterzukommen.

Probier mal, ob der unt64_t % 1000 den Rest richtig bringt, dann kannst Du Dir eine eigene Printfunktion bauen.

Nee, brauch ich garnicht. Sekunden reichen voll und ganz.

Man könnte den Stream noch mit rein geben.

....keinen blassen Schimmer was das ist :frowning:

Man sollte also auf dem ESP8266 unbedingt die uintx_t - Schreibweise nutzen, um sicher zu sein, was man für eine Länge hat.

Was ist denn das?

So, das Beispiel konnte ich nachzollziehen.
Das funktioniert soweit.

Dann hab ich es auf mein Skript übertragen.
....Geht nicht :frowning:

Die entscheidene Fehlermeldung ist glaub ich:

"no type named 'type' in 'struct ArduinoJson::TypeTraits::EnableIf<false, long long unsigned int>'"

....verdammt nochmal. Da brech ich mir schon wieder den Hals mit.

Vielleicht wäre char doch die bessere Variante?
Weil ich das Postprocessing ja auch schon in mit dem char habe.

Lieben Gruß,
Chris

Konkret hab ich es so versucht:

uint64_t zwischen;



      zwischen = data_tuples0[0];         // Variable "LastTimestamp[i]" füllen mit Wert aus JSON (z.B. "1509121688067")
      uint32_t ul = zwischen / 1000;
      Serial.print("Zwischen: ");
      Serial.println(ul);

Führt leider zum Kompiler Abbruch.

Was ich nicht verstehe ist, warum folgendes nicht geht?!

char zwischen;



      zwischen = data_tuples0[0];         // Variable "LastTimestamp[i]" füllen mit Wert aus JSON (z.B. "1509121688067")
      Serial.print("Zwischen: ");
      Serial.println(zwischen);

Lieben Gruß,
Chris

themanfrommoon:
Führt leider zum Kompiler Abbruch.

Die Meldung des Kompilers hälst Du geheim, damit wir Dir nicht antworten?

Gruß Tommy

Edit: Außerdem wissen wir nicht, was Du deklariert hat, welche Libs Du benutzt usw. Das kennst Du doch und wir werden uns das nicht aus anderen Threads zusammensuchen. Dann steige ich eher aus.

Die Meldung des Kompilers hälst Du geheim, damit wir Dir nicht antworten?

Nee, steht schon einen Post vorher drin:
"no type named 'type' in 'struct ArduinoJson::TypeTraits::EnableIf<false, long long unsigned int>'"

Aber nun komm ich doch durch sehr viel try&error weiter.

Es scheint an der Variablenübergabe zu liegen.

zwischen = data_tuples0[0];

funktioniert nicht.

strcpy(zwischen, data_tuples0[0]);

funktioniert endlich :slight_smile:

Warum, weiss ich aber leider nicht?!

Lieben Gruß,
Chris

themanfrommoon:
Warum, weiss ich aber leider nicht?!

Aber ich: Weil Dir sämtliches Grundlagenwissen fehlt.

Schau Dir zu Zeichenketten in C mal meine Zusammenfassung an. Auch ansonsten solltest Du an Deinem Grundlagenwissen arbeiten.
Nur kopieren, ohne zu verstehen führt aufs Abstellgleis.

Gruß Tommy

Schau Dir zu Zeichenketten in C mal meine Zusammenfassung an. Auch ansonsten solltest Du an Deinem Grundlagenwissen arbeiten.

Hab ich schon 2x gemacht.
Verstehe aber nicht was du meinst, oder was mich da hätte erleuchten sollen.

Ich hab vor 25 Jahren ne Menge Basic, Turbo Pascal und Visual Basic programmiert. Dann aber 25 Jahre Pause gemacht. Und bin nun plötzlich, wie die Jungfrau zum Kind in der C++ Welt gelandet.

Ich schreibe das mal mit meinen Worten auf:
Ein String ist eine Zeichenkette. Gelernt habe ich, das diese speicherfressend ist, und das man die nicht benutzen soll. Gut, erledigt.
Mit einem char ist immer ein char Array gemeint (also eine Ansammlung von Zeichen). Ja, kenn ich.
Das man vorher wissen sollte wie groß das Array ist, und wenn es zu klein ist und man trotzdem mehr Dateien reinschreibt und dann nur Käse dabei rauskommt ist mir auch klar.
....aber was zum Geier ist zum Beispiel der Unterschied in der Deklaration mit und ohne dem "*"? Da hab ich jetzt schon mehrfach nach gesucht, aber keine für mich verständliche Antwort gefunden.
Dazu schweigt sich dein Tutorial auch aus, oder ich finde es nicht oder ich verstehe es nicht.
Genau das gleiche mit const. Steht leider auch nicht in dem Tutorial drin. Scheint aber wichtig zu sein?!

Bei der Variablenübergabe verstehe ich auch absolut nicht warum manche Varianten nicht funktionieren.
In dem JSON ist die Zeichenkette bzw. Zahl 13 Stellen lang. Also muss ich das char Array so deklarieren: char zwischen1[13];

Hab ich mal in 6 Varianten getan, und versuche die Variablen zu übergeben:

char zwischen1[13];
zwischen1 = data_tuples0[0];

Geht nicht, der Kompiler bricht mit der Fehlermeldung "incompatible types in assignment of 'ArduinoJson::JsonArraySubscript' to 'char [13]' ". Ich verwende die ArduinoJSON Library. Warum das nicht geht verstehe ich nicht.

Next try:

char zwischen2[13];
strcpy(zwischen2, data_tuples0[0]);

Das geht. ....wieso denn das?

Next try:

const char* zwischen3 = data_tuples0[0];

Das geht auch. ....wieso denn das?

Okay, dann versuche ich nochmal die erste Variante aber mit const und "*". Das ist dann so wie die 3. Variante.

const char* zwischen4;
zwischen4 = data_tuples0[0];

Das geht jetzt auch. Warum diese aber geht und die erste Variante nicht geht ist mir nicht klar.

Nun mit Zahlen:

uint32_t zwischen5 = data_tuples0[0];

Geht, aber nur halb, weil die Variable zu klein ist. Das ist mir klar, das da Blödsinn bei rauskommt.

Dann hab ich probiert:

uint64_t zwischen6 = data_tuples0[0];
uint32_t zwischen7 = zwischen6 / 1000;

Das geht wieder nicht, die Fehlermeldung des Kompilers ist: C:\Users\Chris\Documents\Arduino\libraries\ArduinoJson\src/ArduinoJson/Deserialization/../JsonVariant.hpp:240:3: error: no type named 'type' in 'struct ArduinoJson::TypeTraits::EnableIf<false, long long unsigned int>'
Ich verwende die ArduinoJSON Library. Warum das nicht geht verstehe ich nicht.

Mit Zahlen scheint es also irgendwie nicht zu klappen.
Ich denke, das ist auch kein Problem. Ich kann auch mir char Arrays leben, würde diese aber gerne noch besser verstehen, siehe oben.

Nun kommt allerdings noch ein weiteres Problem hinzu.
Ich habe das Ganze auch noch mehrfach.
Also, die ausgelesenen Zeichen sind timestamps.
Davon habe ich aktuell 7 Stück.
Wenn es Zahlen wären, hätte ich einfach Arrays benutzt, das habe ich z.B. schon folgendermaßen mit anderen Variablen erfolgreich gemacht:

uint16_t TextColor[8];
float Temperatur[8]={0};
float OldTemperatur[8]={99};

.....aber wie geht das denn mit char Arrays?
Das müsste dann ja ein "char Array Array" sein.
Gibt's sowas? Geht sowas?
Oder kann man das nur machen, indem man aus dem char Array wieder eine Zahl macht, und diese in ein Zahlen Array speichert?

Ich hoffe ich konnte mich verständlich ausdrücken?
Ich weiss, das ist auch nicht einfach mit mir.

Lieben Gruß und lieben Dank,
Chris

Mit einem char ist immer ein char Array gemeint (also eine Ansammlung von Zeichen).

Nein. Ein char ist einfach ein Byte mit Vorzeichen. Das hat auch ohne Array seinen Nutzen

Mit "char Arrays" sind meistens "C Strings" gemeint. Wichtig ist dabei aber auch die Null-Terminierung um das Ende zu kennzeichnen

aber was zum Geier ist zum Beispiel der Unterschied in der Deklaration mit und ohne dem "*"?

char* ist ein Zeiger auf char. Also die Adresse einer Variablen. Arrays sind in C/C++ keine Objekte wie in reinen OOP Sprachen. Eine Array Variable entspricht in etwa einem Zeiger auf das erste Element.

Wenn du also versucht ein Array einer anderen Variablen zuzuweisen kopierst du nur die Adresse. Nicht den Inhalt. Und die Zuweisung der Adresse geht je nach Datentyp schief. Du kannst z.B. die Adresse in einen anderen Zeiger kopieren, aber nicht in eine andere Array-Variable.
Deshalb gibt es Funktionen wie memcpy() und strcpy() um alles zu kopieren

Dazu schweigt sich dein Tutorial auch aus, oder ich finde es nicht oder ich verstehe es nicht.

Nein. Das steht dort:

Was drückt nun der wert der Variablen Text aus? Da gibt es einen alten Merksatz: "Der Name eines Arrays ist ein Zeiger (Pointer) auf sein erstes Element." Anders ausgedrückt die Variable text sagt uns, wo der Compiler das Array im Speicher abgelegt hat.

Noch was:

float Temperatur[8]={0};

Das { 0 } setzt übrigens nur das erste Element auf 0. Du meinst damit wahrscheinlich etwas anderes. Braucht man auch nicht unbedingt, denn globale Variablen werden automatisch mit 0 initialisiert

Noch eine kleine Ergänzung:

Leider ist einiges von dem was dir klar ist, falsch. Das erschwert das Verständnis etwas.

Ein
** **char** **
ist ein Datentyp, 1 byte groß um 1 Buchstaben speichern zu können. Für einen Text braucht man davon also mehrere hintereinander. Wenn man die irgendwo im Speicher hat, braucht man nur die Anfangsadresse, um damit arbeiten zu können. Der Datentyp "Anfangsadresse eines Textes" wird in C [b]char*[/b] geschrieben.

Das sind also zwei verschiedene Datentypen.

Man könnte darüber noch viel sagen.
Kannst aber auch erstmal versuchen, das so zu verdauen.

Nur als Bemerkung:

man kann Arrays direkt nichts zuweisen (also auch nicht ihre Bezugsadresse ändern),
weil es konstante Pointer auf ihr erstes Element sind.

Es geht nicht weil der Compiler einen Unterschied zwischen char* und char[] macht. Das mit dem "Array Variablen sind Zeiger auf das erste Element" ist etwas vereinfacht und trifft nicht immer zu. Die Variable zerfällt in vielen Fällen in einen Zeiger. Aber nicht hier.