Forum: Compiler & IDEs JSON Objekt Feld erzeugen und auswerten


von Christian J. (Gast)


Lesenswert?

Hallo,

leider ist für mich C++ böhmische Dörfer und die Denkweise hinter der 
JSON API noch nicht ganz klar. Ich möchte einfach nur einen Satz von 10 
Wetterberichten, der sich bereits im JSON Buffer befindet als Feld 
auswerten.

Bisher habe ich mir nur das zusammen gesucht, was auch klappt:

Das Parsen... ich hole 10 Datensätze von der OpenweatherMap, d.h. 10*3 
Stunde = 30 Stunde Vorhersagen
1
const size_t capacity = JSON_ARRAY_SIZE(3) + 2*JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2) + 3*JSON_OBJECT_SIZE(4) +JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12) + 480;
2
3
DynamicJsonBuffer jsonBuffer(10 * capacity);
4
JsonObject& root = jsonBuffer.parseObject(client);

Wurzel der Liste festlegen:
JsonArray& list = root["list"];

/* 2 Sätze auslesen: now und later */
1
JsonObject& now = list[0];
2
JsonObject& later = list[1];
3
4
PressureNow        = now["main"]["pressure"];
5
TempNow         = now["main"]["temp"];
6
WSpeedNow        = now["wind"]["speed"];
usw.

Was nicht klappt ist ein Feld an zu legen, wo ich zb 10 Sätze 
hineinschreibe :-(  Mit now und later habe ich zwei aber ich will das in 
einem Array haben. also zb feld[n]

JsonObject& feld[10];    <- Compiler Mecker: declaration of feld as 
array of referces.

for (int i = 0; i < 10; i++) {
Auswertung.....
}

Kann da mal jemand helfen? Möglichst mit Code?

: Verschoben durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Christian J. schrieb:
> und die Denkweise hinter der JSON API noch nicht ganz klar

"die JSON API" - C++ selbst kennt kein JSON; Du benutzt also irgendeine 
Library/irgendwelchen Code.

Welchen? Woher kommt der? Ist der dokumentiert?

von Christian J. (Gast)


Lesenswert?

Ja, die Arduino Lib für esp8266.... und da ist alles dokuemntiert, 
erschlagend sogar. Ich will nur dieses eine Problem lösen.

https://arduinojson.org/v5/doc/

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Dann zeig' doch mal das Json, das Du von der Wetterseite erhältst.

von Christian J. (Gast)


Lesenswert?

das ist eines mit 2 Datensätzen, ich kann aber auch 10 abrufen. Und 
genau das will ich jetzt tun. Natürlich erzeuge ich nicht 10 Variablen 
now,later,nochlater,viellater etc. sondern will die 10 Sätze einfach nur 
auslesen und in meine eigenen Vars packen, damit ich auf vertrauten 
Boden komme und weiterverarbeiten kann.
1
JsonArray& list = root["list"];
2
    
3
JsonObject& now = list[0];
4
JsonObject& later = list[1];
5
6
  /* Aktuellen Druck und Temperatur holen */
7
  debug(F("Hole JSON Buffer Daten..."));
8
  /* Aktuelle Daten */
9
  PressureNow        = now["main"]["pressure"];
10
  TempNow         = now["main"]["temp"];      /* Temperatur */
11
  WSpeedNow        = now["wind"]["speed"];
12
  WeatherIDNow      = now["weather"][0]["id"];
13
  CloudsAllNow      = now["clouds"]["all"];
14
  String Date       = now["dt_txt"];
15
  String TextNow       = now["weather"][0]["description"];
16
  /* Vorhersage */
17
  String TextLater     = later["weather"][0]["description"];
18
  CloudsAllLater      = later["clouds"]["all"];
19
  TempLater         = later["main"]["temp"];      /* Temperatur */
1
{
2
  "cod": "200",
3
  "message": 0.0023,
4
  "cnt": 2,
5
  "list": [
6
     {
7
      "dt": 1547726400,
8
      "main": {
9
        "temp": 5.86,
10
        "temp_min": 3.93,
11
        "temp_max": 5.86,
12
        "pressure": 998.26,
13
        "sea_level": 1012.84,
14
        "grnd_level": 998.26,
15
        "humidity": 98,
16
        "temp_kf": 1.93
17
      },
18
      "weather": [
19
        {
20
          "id": 500,
21
          "main": "Rain",
22
          "description": "light rain",
23
          "icon": "10d"
24
        }
25
      ],
26
      "clouds": {
27
        "all": 44
28
      },
29
      "wind": {
30
        "speed": 6.17,
31
        "deg": 241.002
32
      },
33
      "rain": {
34
        "3h": 0.0825
35
      },
36
      "sys": {
37
        "pod": "d"
38
      },
39
      "dt_txt": "2019-01-17 12:00:00"
40
    },
41
 
42
  {
43
      "dt": 1547737200,
44
      "main": {
45
        "temp": 4,
46
        "temp_min": 2.55,
47
        "temp_max": 4,
48
        "pressure": 997.53,
49
        "sea_level": 1012.32,
50
        "grnd_level": 997.53,
51
        "humidity": 100,
52
        "temp_kf": 1.45
53
      },
54
      "weather": [
55
        {
56
          "id": 500,
57
          "main": "Rain",
58
          "description": "light rain",
59
          "icon": "10d"
60
        }
61
      ],
62
      "clouds": {
63
        "all": 92
64
      },
65
      "wind": {
66
        "speed": 4.98,
67
        "deg": 259.003
68
      },
69
      "rain": {
70
        "3h": 1.8475
71
      },
72
      "snow": {
73
        "3h": 0.006
74
      },
75
      "sys": {
76
        "pod": "d"
77
      },
78
      "dt_txt": "2019-01-17 15:00:00"
79
    }
80
  ],
81
  "city": {
82
    "id": 2952444,
83
    "name": "Barntrup",
84
    "coord": {
85
      "lat": 51.991,
86
      "lon": 9.1128
87
    },
88
    "country": "DE",
89
    "population": 9513
90
  }
91
}

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

JsonObject& now = list[0];
JsonObject& later = list[1];

Damit habe ich schon die Infos, die ich brauche für die ersten beiden 
Sätze, die 3h auseinander liegen. 0 für jetzt und 1 für in 3 Stunden. 
Und nun nur noch das ganze erweitern auf 10 Sätze. Aber JsonObject& mit 
dem & hinter dem Typ ist mir aus C nicht bekannt, das scheint eine 
Instanz eines Objektes zu sein. Now wird zum Zeiger auf den Inhalt bzw 
die Methoden dieser Klasse. So mein rudimentäres Verständnis von c++....

Und da soll es alles rein:
1
/* Wetter Datensatz */
2
typedef struct {
3
    int      FC_Hours;        /* Stunden in Zukunft: 0,3,6,9,12,15,.... */
4
    int     wid;          /* Die ID der aktuellen Wetterlage */  
5
    int     Pressure;        /* Druck */
6
    double     Temp;          /* Temperatur */
7
    double    WSpeed;          /* Windgeschwindigkeit */
8
    int     CloudsAll;        /* Bewölkung in % */
9
    String    DateStamp;        /* Zeitstempel als String */ 
10
    String    WetterText;        /* Wetter als Satz */
11
} wetter_t;
12
13
wetter_t wetter[10] = {0,};

von Markus F. (mfro)


Lesenswert?

Christian J. schrieb:
> JsonObject& feld[10];    <- Compiler Mecker

Zu recht.

C++ Standard §8.3.2/4:
    There shall be no references to references, no arrays of references, 
and no pointers to references.

von Christian J. (Gast)


Lesenswert?

Das nützt mir aber auch nichts. Warum sagst du mir nicht wie es richtig 
gemacht wird?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Christian J. schrieb:
> sondern will die 10 Sätze einfach nur auslesen und in meine eigenen Vars
> packen,

Ich würde hier anstelle von
1
   PressureNow =  now["main"]["pressure"];

etwas à la
1
   PressureNow =  List[0]["main"]["pressure"];

ausprobieren.

Und stattt "PressureNow" ein Array von Drücken:
1
for (i = 0; i < Anzahl; i++)
2
{
3
  Pressure[i] = List[i]["main"]["pressure"];
4
}

bzw. sehen, ob es einen tauglichen Listeniterator gibt und den dann 
verwenden.

Oder hab' ich das Problem jetzt komplett missverstanden?

von Christian J. (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Oder hab' ich das Problem jetzt komplett missverstanden?

Nee, ich denke schon richtig. Das problem vieler Anleitungen wie auch 
bei dieser ist, dass sie von leuten geschrieben werden, die so tief in 
der Materie stecken, dass sie die Fragen eines Neulings nicht 
"verstehen". Im Grund ist diese nur, wie die Daten in dem Container 
abgelegt sind (nach dem Parsen) und wie der Zugriff erfolgt. Json an 
sich ist nix Besonders, ein Datenformat wie xml, lesbar von Menschen und 
Maschinen zur strukturierten Ablage von Daten, die eine hierarische 
Ordnung haben können.  Ihc probiers mal heute abend aus, wenn ich Zeit 
habe...

von Christian J. (Gast)


Lesenswert?

Weisst du zufällig was diese 0 da bedeutet?
WeatherIDNow      = now["weather"][0]["id"];
Ist auch nur abgeschrieben.....

PS: Deine Lösung kompiliert schonmal durch.... das gibt Hoffung.

PSS: Und sie funktioniert auch :-)))) Klasse, danke Meister!

von M.K. B. (mkbit)


Lesenswert?

Christian J. schrieb:
> Weisst du zufällig was diese 0 da bedeutet?
> WeatherIDNow      = now["weather"][0]["id"];

Das ist der Index für ein Array.
Hier (http://json.org/) ist die JSON Syntax ganz gut dargestellt. Wenn 
du die Daten genau anschaust, dann siehst du, dass weather ein Array 
ist.

von Christian J. (Gast)


Lesenswert?

Ah ok. Es reicht wennn man das versteht, was man grad braucht denke ich. 
Bin ja kein Entwickler für solche Anwendungen.

Und warum muss ich solche Verrenkungen machen über die foo Variablen? 
Direkte Zuweisung auf den gleichen Typ (global) geht nicht. Da wird 
gemeckert. Es können auch keine rechnungen gemacht werden. Die Ausdrücke 
müssen so da stehen wie sie sind. Also die *3.6 kann nicht geklammert 
werden.
1
  for (int i = 0; i < (HFcN-1);i++) {
2
    wetter[i].wid     =  list[i]["weather"][0]["id"];
3
    wetter[i].Pressure  = list[0]["main"]["pressure"];
4
    wetter[i].Temp     = list[0]["main"]["temp"];
5
    wetter[i].WSpeed   =  list[0]["wind"]["speed"];
6
    wetter[i].WSpeed   *= 3.6;
7
    wetter[i].CloudsAll = list[i]["clouds"]["all"];
8
    String foo1         = list[i]["dt_txt"];
9
    wetter[i].DateStamp = foo1;
10
    String foo2      = list[0]["weather"][0]["description"];
11
    wetter[i].WetterText = foo2;
12
  }

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Christian J. schrieb:
> Direkte Zuweisung auf den gleichen Typ (global) geht nicht. Da wird
> gemeckert.

Aha. Der Compiler gibt eine Meldung "Gemecker" aus, oder wie muss man 
sich das vorstellen?

Fehlermeldungen haben in der Regel eine Bedeutung, der man entnehmen 
kann, was das Problem ist.

von Christian J. (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Aha. Der Compiler gibt eine Meldung "Gemecker" aus, oder wie muss man
> sich das vorstellen?

Es ist ein ganzer Wust, der sich nicht auf die Zeile bezieht, sondern 
aus den Quelltext der Json Lib. U.a. dass keine passende Methode 
gefunden wurde. Nur der Typ String macht diese probleme, die anderen 
nicht.

von Christian J. (Gast)


Lesenswert?

Ich habe mal etwas gekürzt :-)

Arduino: 1.8.5 (Windows 7), Board: "NodeMCU 1.0 (ESP-12E Module), 80 
MHz, Flash, 4M (1M SPIFFS), v2 Lower Memory, Disabled, None, Only 
Sketch, 256000"

Build-Optionen wurden verändert, alles wird neu kompiliert
K:\ESP8266\WetterOled\tools.ino: In function 'int GetWeatherData()':

tools:186: error: ambiguous overload for 'operator=' (operand types are 
'String' and 'ArduinoJson::Internals::EnableIf<true, 
ArduinoJson::Internals::JsonObjectSubscript<const char*> >::type {aka 
ArduinoJson::Internals::JsonObjectSubscript<const char*>}')

   wetter[i].DateStamp        =  list[i]["dt_txt"];

exit status 1
ambiguous overload for 'operator=' (operand types are 'String' and 
'ArduinoJson::Internals::EnableIf<true, 
ArduinoJson::Internals::JsonObjectSubscript<const char*> >::type {aka 
ArduinoJson::Internals::JsonObjectSubscript<const char*>}')

Dieser Bericht wäre detaillierter, wenn die Option
"Ausführliche Ausgabe während der Kompilierung"
in Datei -> Voreinstellungen aktiviert wäre.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Probier' doch mal aus, was passiert, wenn Du in die betreffende Zeile 
einen typecast nach String einbaust, d.h.

>     wetter[i].DateStamp = (String) list[i]["dt_txt"];

Was passiert dann?

von Christian J. (Gast)


Lesenswert?

Rufus Τ. F. schrieb:

> Was passiert dann?

K:\ESP8266\WetterOled\tools.ino: In function 'int GetWeatherData()':

tools:186: error: call of overloaded 
'String(ArduinoJson::Internals::EnableIf<true, 
ArduinoJson::Internals::JsonObjectSubscript<const char*> >::type)' is 
ambiguous

   wetter[i].DateStamp  =  (String)list[i]["dt_txt"];

Das Problem bezieht sich nur auf die String Klasse, die ja ohnehin mit 
Vorsicht zu genießen ist und auf "double".

Nur das ist kompilierbar und liefert das richtige Eregbnis:
String foo1         =  list[i]["dt_txt"];
wetter[i].DateStamp =  foo1;

Das hier aber läuft durch. Ohne den Cast aber nicht.
wetter[i].WSpeed   =  3.6 * (double)list[i]["wind"]["speed"];

ich hoffe doch, dass die Json Klasse einen Destruktor hat, der den 
dynamischen Speicher wieder frei gibt, wenn die Routine verlassen wird. 
Due legt das nämlich auf dem Heap an wie ich meine und nicht auf dem 
Stack.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Christian J. schrieb:
> Ich hoffe doch, dass die Json Klasse einen Destruktor hat

Du hast die Sourcen - sieh sie Dir an.

von Christian J. (Gast)


Lesenswert?

Naja, einfach geht es nicht mehr als hier:
https://arduinojson.org/v5/assistant/

Man trägt seinen Satz ein und bekommt alles geliefert mit fertigem Code, 
um kreuz und quer darauf zu zu greifen.....

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Christian J. schrieb:
> Naja, einfach geht es nicht mehr als hier:

Was es nicht alles gibt. Faszinierend.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.