diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino index 532ff68..d33f846 100644 --- a/RX_FSK/RX_FSK.ino +++ b/RX_FSK/RX_FSK.ino @@ -1465,10 +1465,10 @@ uint8_t ubx_hardreset[] = {UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x04, 4, 0, 0xff, 0xf uint8_t ubx_enable_gpgst[] = {UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x01, 3, 0, 0xF0, 0x07, 2, 0x03, 0x1F}; void dumpGPS() { - while (Serial2.available()) { - char c = Serial2.read(); - Serial.printf("%02x ", (uint8_t)c); - } + while (Serial2.available()) { + char c = Serial2.read(); + Serial.printf("%02x ", (uint8_t)c); + } } void initGPS() { if (sonde.config.gps_rxd < 0) return; // GPS disabled @@ -2232,6 +2232,8 @@ void loopDecoder() { mqttclient.publishPacket(s); } #endif + } else { + sondehub_finish_data(&shclient, s, &sonde.config.sondehub); } // always send data, even if not valid.... if (rdzclient.connected()) { @@ -2739,6 +2741,7 @@ void loopWifiScan() { while (WiFi.status() != WL_CONNECTED && cnt < MAXWIFIDELAY) { delay(500); Serial.print("."); +#if 0 if (cnt == 5) { // my FritzBox needs this for reconnecting WiFi.disconnect(true); @@ -2748,6 +2751,7 @@ void loopWifiScan() { Serial.print(" with password "); Serial.println(fetchWifiPw(index)); delay(500); } +#endif disp.rdis->drawString(15 * dispxs, lastl + dispys, _scan[cnt & 1]); cnt++; } @@ -3000,19 +3004,19 @@ void loop() { #endif #if FEATURE_SONDEHUB - if (sonde.config.sondehub.active) { - unsigned long time_now = millis(); - // time_delta will be correct, even if time_now overflows - unsigned long time_delta = time_now - time_last_update; - if ((sonde.config.sondehub.chase == 0) && (time_delta >= SONDEHUB_STATION_UPDATE_TIME) && (wifi_state != WIFI_APMODE)) { // 60 min - sondehub_station_update(&shclient, &sonde.config.sondehub); - time_last_update = time_now; - } - else if ((sonde.config.sondehub.chase == 1) && (time_delta >= SONDEHUB_MOBILE_STATION_UPDATE_TIME) && (wifi_state != WIFI_APMODE)) { // 30 sec - sondehub_station_update(&shclient, &sonde.config.sondehub); - time_last_update = time_now; - } + if (sonde.config.sondehub.active) { + unsigned long time_now = millis(); + // time_delta will be correct, even if time_now overflows + unsigned long time_delta = time_now - time_last_update; + if ((sonde.config.sondehub.chase == 0) && (time_delta >= SONDEHUB_STATION_UPDATE_TIME) && (wifi_state != WIFI_APMODE)) { // 60 min + sondehub_station_update(&shclient, &sonde.config.sondehub); + time_last_update = time_now; } + else if ((sonde.config.sondehub.chase == 1) && (time_delta >= SONDEHUB_MOBILE_STATION_UPDATE_TIME) && (wifi_state != WIFI_APMODE)) { // 30 sec + sondehub_station_update(&shclient, &sonde.config.sondehub); + time_last_update = time_now; + } + } #endif } @@ -3022,7 +3026,7 @@ void loop() { Update station data to the sondehub v2 DB */ void sondehub_station_update(WiFiClient *client, struct st_sondehub *conf) { - #define STATION_DATA_LEN 300 +#define STATION_DATA_LEN 300 char data[STATION_DATA_LEN]; char *w; @@ -3046,7 +3050,7 @@ void sondehub_station_update(WiFiClient *client, struct st_sondehub *conf) { "\"uploader_contact_email\": \"%s\",", version_name, version_id, conf->callsign, conf->email); w += strlen(w); - if ((conf->chase == 0) && (conf->lat[0] != '\0') && (conf->lon[0] != '\0')){ + if ((conf->chase == 0) && (conf->lat[0] != '\0') && (conf->lon[0] != '\0')) { if (conf->alt[0] != '\0') { sprintf(w, "\"uploader_position\": [%s,%s,%s]," @@ -3065,7 +3069,7 @@ void sondehub_station_update(WiFiClient *client, struct st_sondehub *conf) { sprintf(w, "\"uploader_position\": [%.6f,%.6f,%d]," "\"uploader_antenna\": \"%s\"," - "\"mobile\": \"true\"" + "\"mobile\": true" "}", gpsPos.lat, gpsPos.lon, gpsPos.alt, conf->antenna); } @@ -3088,15 +3092,16 @@ void sondehub_station_update(WiFiClient *client, struct st_sondehub *conf) { String response = client->readString(); Serial.println(response); Serial.println("Response done..."); - //client->stop(); + //client->stop();r } /* Update sonde data to the sondehub v2 DB */ -enum SHState { SH_DISCONNECTED, SH_CONNECTING, SH_CONN_IDLE, SH_CONN_WAITACK }; +enum SHState { SH_DISCONNECTED, SH_CONNECTING, SH_CONN_IDLE, SH_CONN_APPENDING, SH_CONN_WAITACK }; SHState shState = SH_DISCONNECTED; +time_t shStart = 0; /* Sonde.h: enum SondeType { STYPE_DFM, STYPE_DFM09_OLD, STYPE_RS41, STYPE_RS92, STYPE_M10, STYPE_M20, STYPE_DFM06_OLD, STYPE_MP3H }; */ const char *sondeTypeStrSH[NSondeTypes] = { "DFM", "DFM", "RS41", "RS92", "M10", "M20", "DFM", "MRZ" }; @@ -3115,6 +3120,10 @@ const char *dfmSubtypeStrSH[16] = { NULL, NULL, NULL, NULL, NULL, NULL, #define SONDEHUB_TIME_THRESHOLD (3) void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *conf) { Serial.println("sondehub_send_data()"); + Serial.printf("shState = %d\n", shState); + + // max age of data in JSON request (in seconds) +#define SONDEHUB_MAXAGE 15 #define MSG_SIZE 550 char rs_msg[MSG_SIZE]; @@ -3135,12 +3144,21 @@ void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *co } } + struct tm timeinfo; + time_t now; + time(&now); + gmtime_r(&now, &timeinfo); + if (timeinfo.tm_year <= (2016 - 1900)) { + Serial.println("Failed to obtain time"); + return; + } + // Check if current sonde data is valid. If not, don't do anything.... if (*s->ser == 0) return; // Don't send anything without serial number if (((int)s->lat == 0) && ((int)s->lon == 0)) return; // Sometimes these values are zeroes. Don't send those to the sondehub if ((int)s->alt > 50000) return; // If alt is too high don't send to SondeHub // M20 data does not include #sat information - if ( s->type!=STYPE_M20 && (int)s->sats < 4) return; // If not enough sats don't send to SondeHub + if ( s->type != STYPE_M20 && (int)s->sats < 4) return; // If not enough sats don't send to SondeHub // If not connected to sondehub, try reconnecting. // TODO: do this outside of main loop @@ -3160,14 +3178,6 @@ void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *co return; } - struct tm timeinfo; - time_t now; - time(&now); - gmtime_r(&now, &timeinfo); - if (timeinfo.tm_year <= (2016 - 1900)) { - Serial.println("Failed to obtain time"); - return; - } if ( abs(now - (time_t)s->time) > (3600 * SONDEHUB_TIME_THRESHOLD) ) { Serial.printf("Sonde time %d too far from current UTC time %ld", s->time, now); return; @@ -3185,7 +3195,7 @@ void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *co w = rs_msg; sprintf(w, - "[ {" + " {" "\"software_name\": \"%s\"," "\"software_version\": \"%s\"," "\"uploader_callsign\": \"%s\"," @@ -3195,28 +3205,36 @@ void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *co "\"datetime\": \"%04d-%02d-%02dT%02d:%02d:%02d.000Z\"," "\"lat\": %.6f," "\"lon\": %.6f," - "\"alt\": %.2f," + "\"alt\": %.3f," "\"frequency\": %.3f," - "\"vel_h\": %.1f," - "\"vel_v\": %.1f," - "\"heading\": %.1f," - "\"sats\": %d," + "\"vel_h\": %.3f," + "\"vel_v\": %.3f," + "\"heading\": %.3f," "\"rssi\": %.1f,", version_name, version_id, conf->callsign, timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, manufacturer_string[s->type], s->ser, ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec + s->sec, (float)s->lat, (float)s->lon, (float)s->alt, (float)s->freq, (float)s->hs, (float)s->vs, - (float)s->dir, (int)s->sats, -((float)s->rssi / 2) + (float)s->dir, -((float)s->rssi / 2) ); w += strlen(w); + + if (s->type != STYPE_M20) { + sprintf(w, "\"sats\": %d,", (int)s->sats); + w += strlen(w); + } if ( TYPE_IS_DFM(s->type) || TYPE_IS_METEO(s->type) || s->type == STYPE_MP3H ) { // send frame as gps timestamp for these sonde, identical to autorx // For M10, this is real GPS time (seconds since Jqn 6 1980, without adjusting for leap seconds) // DFM and MP3H send real UTC (with leap seconds considered), so for them the frame number actually // is gps time plus number of leap seconds since the beginning of GPS time. - sprintf(w, "\"frame\": %d,", int(t - 315964800)); + int frame = (int)(t - 315964800); + if (s->type == STYPE_M10) { + frame += 18; + }; + sprintf(w, "\"frame\": %d,", frame); } else { sprintf(w, "\"frame\": %d,", s->frame); } @@ -3236,59 +3254,109 @@ void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *co if (((int)s->temperature != 0) && ((int)s->relativeHumidity != 0)) { sprintf(w, - "\"temp\": %.2f," - "\"humidity\": %.2f,", + "\"temp\": %.1f," + "\"humidity\": %.1f,", float(s->temperature), float(s->relativeHumidity) ); w += strlen(w); } - if ((conf->chase == 0) && (conf->lat[0] != '\0') && (conf->lon[0] != '\0')){ + if ((conf->chase == 0) && (conf->lat[0] != '\0') && (conf->lon[0] != '\0')) { if (conf->alt[0] != '\0') { sprintf(w, "\"uploader_position\": [%s,%s,%s]," "\"uploader_antenna\": \"%s\"" - "}]", + "}", conf->lat, conf->lon, conf->alt, conf->antenna - ); + ); } else { sprintf(w, "\"uploader_position\": [%s,%s,null]," "\"uploader_antenna\": \"%s\"" - "}]", + "}", conf->lat, conf->lon, conf->antenna - ); + ); } } else if (gpsPos.valid && gpsPos.lat != 0 && gpsPos.lon != 0) { sprintf(w, "\"uploader_position\": [%.6f,%.6f,%d]," "\"uploader_antenna\": \"%s\"" - "}]", + "}", gpsPos.lat, gpsPos.lon, gpsPos.alt, conf->antenna - ); + ); } else { - sprintf(w, + sprintf(w, "\"uploader_antenna\": \"%s\"" - "}]", + "}", conf->antenna ); } - - client->println("PUT /sondes/telemetry HTTP/1.1"); - client->print("Host: "); - client->println(conf->host); - client->println("accept: text/plain"); - client->println("Content-Type: application/json"); - client->print("Content-Length: "); - client->println(strlen(rs_msg)); - client->println(); - client->println(rs_msg); - Serial.println(rs_msg); - shState = SH_CONN_WAITACK; + if (shState != SH_CONN_APPENDING) { + sondehub_send_header(client, s, conf); + sondehub_send_next(client, s, conf, rs_msg, strlen(rs_msg), 1); + shState = SH_CONN_APPENDING; + shStart = now; + } else { + sondehub_send_next(client, s, conf, rs_msg, strlen(rs_msg), 0); + } + if (now - shStart > SONDEHUB_MAXAGE) { // after MAXAGE seconds + sondehub_send_last(client, s, conf); + shState = SH_CONN_WAITACK; + shStart = 0; + } + //client->println(rs_msg); + //Serial.println(rs_msg); //String response = client->readString(); //Serial.println(response); } + +void sondehub_finish_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *conf) { + // If there is an "old" pending collection of JSON data sets, send it even if no now data is received + if (shState == SH_CONN_APPENDING) { + time_t now; + time(&now); + if (now - shStart > SONDEHUB_MAXAGE + 3) { // after MAXAGE seconds + sondehub_send_last(client, s, conf); + shState = SH_CONN_WAITACK; + shStart = 0; + } + } +} + +void sondehub_send_header(WiFiClient *client, SondeInfo *s, struct st_sondehub *conf) { + Serial.print("PUT /sondes/telemetry HTTP/1.1\r\n" + "Host: "); + Serial.println(conf->host); + Serial.println("accept: text/plain\r\n" + "Content-Type: application/json\r\n" + "Transfer-Encoding: chunked\r\n"); + client->print("PUT /sondes/telemetry HTTP/1.1\r\n" + "Host: "); + client->println(conf->host); + client->println("accept: text/plain\r\n" + "Content-Type: application/json\r\n" + "Transfer-Encoding: chunked\r\n"); +} +void sondehub_send_next(WiFiClient *client, SondeInfo *s, struct st_sondehub *conf, char *chunk, int chunklen, int first) { + // send next chunk of JSON request + client->printf("%x\r\n", chunklen + 1); + client->write(first ? "[" : ",", 1); + client->write(chunk, chunklen); + client->print("\r\n"); + + Serial.printf("%x\r\n", chunklen + 1); + Serial.write(first ? "[" : ",", 1); + Serial.write(chunk, chunklen); + Serial.print("\r\n"); +} +void sondehub_send_last(WiFiClient *client, SondeInfo *s, struct st_sondehub *conf) { + // last chunk. just the closing "]" of the json request + client->printf("1\r\n]\r\n0\r\n\r\n"); + Serial.printf("1\r\n]\r\n0\r\n\r\n"); +} + + // End of sondehub v2 related codes #endif diff --git a/RX_FSK/version.h b/RX_FSK/version.h index 60beae8..c6d9c0b 100644 --- a/RX_FSK/version.h +++ b/RX_FSK/version.h @@ -1,4 +1,4 @@ const char *version_name = "rdzTTGOsonde"; -const char *version_id = "devel20210726"; +const char *version_id = "devel20210728"; const int SPIFFS_MAJOR=2; const int SPIFFS_MINOR=11; diff --git a/libraries/SondeLib/M10M20.cpp b/libraries/SondeLib/M10M20.cpp index c7e902b..4d7722d 100644 --- a/libraries/SondeLib/M10M20.cpp +++ b/libraries/SondeLib/M10M20.cpp @@ -320,7 +320,7 @@ int M10M20::decodeframeM10(uint8_t *data) { sonde.si()->vs = getint16(data+8) * VMUL; sonde.si()->hs = sqrt(ve*ve+vn*vn); sonde.si()->sats = data[30]; - float dir = atan2(vn, ve)*(1.0/RAD); + float dir = atan2(ve, vn)*(1.0/RAD); if(dir<0) dir+=360; sonde.si()->dir = dir; sonde.si()->validPos = 0x3f; @@ -566,7 +566,7 @@ int M10M20::decodeframeM20(uint8_t *data) { //0x18 2 byte sonde.si()->vs = getint16(data+24) * VMUL_M20; sonde.si()->hs = sqrt(ve*ve+vn*vn); - float dir = atan2(vn, ve)*(1.0/RAD); + float dir = atan2(ve, vn)*(1.0/RAD); if(dir<0) dir+=360; sonde.si()->dir = dir; sonde.si()->validPos = 0x3f;