kopia lustrzana https://github.com/dl9rdz/rdz_ttgo_sonde
reorg sondehub
rodzic
61b733cf92
commit
af4940c889
|
@ -1,5 +1,6 @@
|
||||||
#include "features.h"
|
#include "features.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <WiFiUdp.h>
|
#include <WiFiUdp.h>
|
||||||
|
@ -42,6 +43,9 @@
|
||||||
#if FEATURE_APRS
|
#if FEATURE_APRS
|
||||||
#include "src/conn-aprs.h"
|
#include "src/conn-aprs.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if FEATURE_SONDEHUB
|
||||||
|
#include "src/conn-sondehub.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
//#define ESP_MEM_DEBUG 1
|
//#define ESP_MEM_DEBUG 1
|
||||||
//int e;
|
//int e;
|
||||||
|
@ -78,14 +82,15 @@ WiFiClient client;
|
||||||
const char *sondeTypeStrSH[NSondeTypes] = { "DFM", "RS41", "RS92", "Mxx"/*never sent*/, "M10", "M20", "MRZ" };
|
const char *sondeTypeStrSH[NSondeTypes] = { "DFM", "RS41", "RS92", "Mxx"/*never sent*/, "M10", "M20", "MRZ" };
|
||||||
|
|
||||||
|
|
||||||
#if FEATURE_SONDEHUB
|
// moved to connSondehub.cpp
|
||||||
#define SONDEHUB_STATION_UPDATE_TIME (60*60*1000) // 60 min
|
//#if FEATURE_SONDEHUB
|
||||||
#define SONDEHUB_MOBILE_STATION_UPDATE_TIME (30*1000) // 30 sec
|
//#define SONDEHUB_STATION_UPDATE_TIME (60*60*1000) // 60 min
|
||||||
WiFiClient shclient; // Sondehub v2
|
//#define SONDEHUB_MOBILE_STATION_UPDATE_TIME (30*1000) // 30 sec
|
||||||
int shImportInterval = 0;
|
//WiFiClient shclient; // Sondehub v2
|
||||||
char shImport = 0;
|
//int shImportInterval = 0;
|
||||||
unsigned long time_last_update = 0;
|
//char shImport = 0;
|
||||||
#endif
|
//unsigned long time_last_update = 0;
|
||||||
|
//#endif
|
||||||
|
|
||||||
// JSON over TCP for communicating with the rdzSonde (rdzwx-go) Android app
|
// JSON over TCP for communicating with the rdzSonde (rdzwx-go) Android app
|
||||||
WiFiServer rdzserver(14570);
|
WiFiServer rdzserver(14570);
|
||||||
|
@ -438,32 +443,6 @@ const char *createWIFIForm() {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
// moved to map.html (active warning is still TODO
|
|
||||||
const char *createSondeHubMap() {
|
|
||||||
SondeInfo *s = &sonde.sondeList[0];
|
|
||||||
char *ptr = message;
|
|
||||||
strcpy(ptr, HTMLHEAD); strcat(ptr, "</head>");
|
|
||||||
HTMLBODY(ptr, "map.html");
|
|
||||||
if (!sonde.config.sondehub.active) {
|
|
||||||
strcat(ptr, "<div class=\"warning\">NOTE: SondeHub uploading is not enabled, detected sonde will not be visable on map</div>");
|
|
||||||
if ((*s->d.ser == 0) && ( !isnan(sonde.config.rxlat))) {
|
|
||||||
sprintf(ptr + strlen(ptr), "<iframe src=\"https://sondehub.org/#!mc=%f,%f&mz=8\" style=\"border:1px solid #00A3D3;border-radius:20px;height:95vh\"></iframe>", sonde.config.rxlat, sonde.config.rxlon);
|
|
||||||
} else {
|
|
||||||
sprintf(ptr + strlen(ptr), "<iframe src=\"https://sondehub.org/%s\" style=\"border:1px solid #00A3D3;border-radius:20px;height:95vh\"></iframe>", s->d.ser);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((*s->d.ser == 0) && (!isnan(sonde.config.rxlat))) {
|
|
||||||
sprintf(ptr, "<iframe src=\"https://sondehub.org/#!mc=%f,%f&mz=8\" style=\"border:1px solid #00A3D3;border-radius:20px;height:98vh;width:100%%\"></iframe>", sonde.config.rxlat, sonde.config.rxlon);
|
|
||||||
} else {
|
|
||||||
sprintf(ptr, "<iframe src=\"https://sondehub.org/%s\" style=\"border:1px solid #00A3D3;border-radius:20px;height:98vh;width:100%%\"></iframe>", s->d.ser);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HTMLBODYEND(ptr);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char *handleWIFIPost(AsyncWebServerRequest * request) {
|
const char *handleWIFIPost(AsyncWebServerRequest * request) {
|
||||||
char label[10];
|
char label[10];
|
||||||
// parameters: a_i, f_1, t_i (active/frequency/type)
|
// parameters: a_i, f_1, t_i (active/frequency/type)
|
||||||
|
@ -602,9 +581,6 @@ void setupConfigData() {
|
||||||
sonde.setConfig(line.c_str());
|
sonde.setConfig(line.c_str());
|
||||||
}
|
}
|
||||||
sonde.checkConfig(); // eliminate invalid entries
|
sonde.checkConfig(); // eliminate invalid entries
|
||||||
#if FEATURE_SONDEHUB
|
|
||||||
shImportInterval = 5; // refresh now in 5 seconds
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2062,10 +2038,6 @@ void loopDecoder() {
|
||||||
Serial.println("");
|
Serial.println("");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FEATURE_SONDEHUB
|
|
||||||
sondehub_reply_handler(&shclient);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// wifi active and good packet received => send packet
|
// wifi active and good packet received => send packet
|
||||||
SondeInfo *s = &sonde.sondeList[rxtask.receiveSonde];
|
SondeInfo *s = &sonde.sondeList[rxtask.receiveSonde];
|
||||||
if ((res & 0xff) == 0 && connected) {
|
if ((res & 0xff) == 0 && connected) {
|
||||||
|
@ -2076,40 +2048,6 @@ void loopDecoder() {
|
||||||
#if FEATURE_APRS
|
#if FEATURE_APRS
|
||||||
connAPRS.updateSonde(s);
|
connAPRS.updateSonde(s);
|
||||||
#endif
|
#endif
|
||||||
#if 0
|
|
||||||
// moved to conn-aprs.cpp
|
|
||||||
char *str = aprs_senddata(s, sonde.config.call, sonde.config.objcall, sonde.config.udpfeed.symbol);
|
|
||||||
char raw[201];
|
|
||||||
int rawlen = aprsstr_mon2raw(str, raw, APRS_MAXLEN);
|
|
||||||
Serial.println("Sending AXUDP");
|
|
||||||
//Serial.println(raw);
|
|
||||||
udp.beginPacket(sonde.config.udpfeed.host, sonde.config.udpfeed.port);
|
|
||||||
udp.write((const uint8_t *)raw, rawlen);
|
|
||||||
udp.endPacket();
|
|
||||||
if (tncclient.connected()) {
|
|
||||||
Serial.println("Sending position via TCP");
|
|
||||||
char raw[201];
|
|
||||||
int rawlen = aprsstr_mon2kiss(str, raw, APRS_MAXLEN);
|
|
||||||
Serial.print("sending: "); Serial.println(raw);
|
|
||||||
tncclient.write(raw, rawlen);
|
|
||||||
}
|
|
||||||
if (sonde.config.tcpfeed.active) {
|
|
||||||
static unsigned long lasttcp = 0;
|
|
||||||
if ( tcpclient.disconnected()) {
|
|
||||||
tcpclient.connect(sonde.config.tcpfeed.host, sonde.config.tcpfeed.port);
|
|
||||||
}
|
|
||||||
else if ( tcpclient.connected() ) {
|
|
||||||
unsigned long now = millis();
|
|
||||||
Serial.printf("aprs: now-last = %ld\n", (now - lasttcp));
|
|
||||||
if ( (now - lasttcp) > sonde.config.tcpfeed.highrate * 1000L ) {
|
|
||||||
strcat(str, "\r\n");
|
|
||||||
Serial.print(str);
|
|
||||||
tcpclient.write(str, strlen(str));
|
|
||||||
lasttcp = now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FEATURE_CHASEMAPPER
|
#if FEATURE_CHASEMAPPER
|
||||||
if (sonde.config.cm.active) {
|
if (sonde.config.cm.active) {
|
||||||
|
@ -2119,7 +2057,8 @@ void loopDecoder() {
|
||||||
}
|
}
|
||||||
#if FEATURE_SONDEHUB
|
#if FEATURE_SONDEHUB
|
||||||
if (sonde.config.sondehub.active) {
|
if (sonde.config.sondehub.active) {
|
||||||
sondehub_send_data(&shclient, s, &sonde.config.sondehub);
|
connSondehub.updateSonde( s ); // invoke sh_send_data....
|
||||||
|
// sondehub_send_data(&shclient, s, &sonde.config.sondehub);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2129,20 +2068,17 @@ void loopDecoder() {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
#if FEATURE_SONDEHUB
|
#if FEATURE_SONDEHUB
|
||||||
sondehub_finish_data(&shclient, s, &sonde.config.sondehub);
|
connSondehub.updateSonde( NULL );
|
||||||
|
// sondehub_finish_data(&shclient, s, &sonde.config.sondehub);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Send own position periodically
|
// Send own position periodically
|
||||||
#if FEATURE_MQTT
|
#if FEATURE_MQTT
|
||||||
connMQTT.updateStation( NULL );
|
connMQTT.updateStation( NULL );
|
||||||
#endif
|
#endif
|
||||||
#if FEATURE_APRS
|
#if FEATURE_APRS
|
||||||
connAPRS.updateStation( NULL );
|
connAPRS.updateStation( NULL );
|
||||||
//if (sonde.config.tcpfeed.active) {
|
|
||||||
// aprs_station_update();
|
|
||||||
//}
|
|
||||||
#endif
|
#endif
|
||||||
// always send data, even if not valid....
|
// always send data, even if not valid....
|
||||||
if (rdzclient.connected()) {
|
if (rdzclient.connected()) {
|
||||||
|
@ -2279,9 +2215,10 @@ String translateEncryptionType(wifi_auth_mode_t encryptionType) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum t_wifi_state { WIFI_DISABLED, WIFI_SCAN, WIFI_CONNECT, WIFI_CONNECTED, WIFI_APMODE };
|
// in core.h
|
||||||
|
//enum t_wifi_state { WIFI_DISABLED, WIFI_SCAN, WIFI_CONNECT, WIFI_CONNECTED, WIFI_APMODE };
|
||||||
|
|
||||||
static t_wifi_state wifi_state = WIFI_DISABLED;
|
t_wifi_state wifi_state = WIFI_DISABLED;
|
||||||
|
|
||||||
void enableNetwork(bool enable) {
|
void enableNetwork(bool enable) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
|
@ -2299,21 +2236,22 @@ void enableNetwork(bool enable) {
|
||||||
connMQTT.netsetup();
|
connMQTT.netsetup();
|
||||||
#endif
|
#endif
|
||||||
#if FEATURE_SONDEHUB
|
#if FEATURE_SONDEHUB
|
||||||
if (sonde.config.sondehub.active && wifi_state != WIFI_APMODE) {
|
//if (sonde.config.sondehub.active && wifi_state != WIFI_APMODE) {
|
||||||
time_last_update = millis() + 1000; /* force sending update */
|
// time_last_update = millis() + 1000; /* force sending update */
|
||||||
sondehub_station_update(&shclient, &sonde.config.sondehub);
|
// sondehub_station_update(&shclient, &sonde.config.sondehub);
|
||||||
}
|
//}
|
||||||
|
connSondehub.netsetup();
|
||||||
#endif
|
#endif
|
||||||
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
|
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
|
||||||
connected = true;
|
connected = true;
|
||||||
|
#if FEATURE_APRS
|
||||||
|
connAPRS.netsetup();
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
MDNS.end();
|
MDNS.end();
|
||||||
connected = false;
|
connected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FEATURE_APRS
|
|
||||||
connAPRS.netsetup();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Serial.println("enableNetwork done");
|
Serial.println("enableNetwork done");
|
||||||
}
|
}
|
||||||
|
@ -2962,7 +2900,8 @@ void loop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if FEATURE_SONDEHUB
|
#if 0
|
||||||
|
// removed here, now in connSondehub
|
||||||
|
|
||||||
// Sondehub v2 DB related codes
|
// Sondehub v2 DB related codes
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
enum t_wifi_state { WIFI_DISABLED, WIFI_SCAN, WIFI_CONNECT, WIFI_CONNECTED, WIFI_APMODE };
|
||||||
|
extern t_wifi_state wifi_state;
|
||||||
|
|
||||||
|
extern const char *sondeTypeStrSH[];
|
|
@ -129,6 +129,10 @@ void ConnAPRS::updateStation( PosInfo *pi ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ConnAPRS::getStatus() {
|
||||||
|
return String("");
|
||||||
|
}
|
||||||
|
|
||||||
void ConnAPRS::aprs_station_update() {
|
void ConnAPRS::aprs_station_update() {
|
||||||
int chase = sonde.config.chase;
|
int chase = sonde.config.chase;
|
||||||
// automatically decided if CHASE or FIXED mode is used (for config AUTO)
|
// automatically decided if CHASE or FIXED mode is used (for config AUTO)
|
||||||
|
|
|
@ -29,6 +29,8 @@ public:
|
||||||
/* Called approx 1x / second* */
|
/* Called approx 1x / second* */
|
||||||
void updateStation( PosInfo *pi );
|
void updateStation( PosInfo *pi );
|
||||||
|
|
||||||
|
String getStatus();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void aprs_station_update();
|
void aprs_station_update();
|
||||||
};
|
};
|
||||||
|
|
|
@ -64,5 +64,9 @@ void ConnChasemapper::updateSonde(SondeInfo *si) {
|
||||||
void ConnChasemapper::updateStation(PosInfo *pi) {
|
void ConnChasemapper::updateStation(PosInfo *pi) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ConnChasemapper::getStatus() {
|
||||||
|
return String("");
|
||||||
|
}
|
||||||
|
|
||||||
ConnChasemapper connChasemapper;
|
ConnChasemapper connChasemapper;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,6 +10,7 @@ public:
|
||||||
void netsetup();
|
void netsetup();
|
||||||
void updateSonde( SondeInfo *si );
|
void updateSonde( SondeInfo *si );
|
||||||
void updateStation( PosInfo *pi );
|
void updateStation( PosInfo *pi );
|
||||||
|
String getStatus();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ConnChasemapper connChasemapper;
|
extern ConnChasemapper connChasemapper;
|
||||||
|
|
|
@ -82,6 +82,10 @@ void MQTT::updateStation( PosInfo *pi ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String MQTT::getStatus() {
|
||||||
|
return String("");
|
||||||
|
}
|
||||||
|
|
||||||
// Internal (private) functions
|
// Internal (private) functions
|
||||||
//void MQTT::connectToMqtt() {
|
//void MQTT::connectToMqtt() {
|
||||||
// Serial.println("Connecting to MQTT...");
|
// Serial.println("Connecting to MQTT...");
|
||||||
|
|
|
@ -25,6 +25,7 @@ public:
|
||||||
/* Called approx 1x / second* */
|
/* Called approx 1x / second* */
|
||||||
virtual void updateStation( PosInfo *pi );
|
virtual void updateStation( PosInfo *pi );
|
||||||
|
|
||||||
|
virtual String getStatus();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WiFiClient mqttWifiClient;
|
WiFiClient mqttWifiClient;
|
||||||
|
|
|
@ -0,0 +1,585 @@
|
||||||
|
#include "../features.h"
|
||||||
|
|
||||||
|
#if FEATURE_SONDEHUB
|
||||||
|
|
||||||
|
#include "conn-sondehub.h"
|
||||||
|
#include "posinfo.h"
|
||||||
|
#include "../core.h"
|
||||||
|
#include "DFM.h"
|
||||||
|
#include "RS41.h"
|
||||||
|
#include <ESPmDNS.h>
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
#include "ShFreqImport.h"
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <lwip/dns.h>
|
||||||
|
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
extern const char *version_name;
|
||||||
|
extern const char *version_id;
|
||||||
|
|
||||||
|
#define SONDEHUB_STATION_UPDATE_TIME (60*60*1000) // 60 min
|
||||||
|
#define SONDEHUB_MOBILE_STATION_UPDATE_TIME (30*1000) // 30 sec
|
||||||
|
WiFiClient shclient; // Sondehub v2
|
||||||
|
int shImportInterval = 0;
|
||||||
|
char shImport = 0;
|
||||||
|
unsigned long time_last_update = 0;
|
||||||
|
|
||||||
|
void ConnSondehub::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnSondehub::netsetup() {
|
||||||
|
if (sonde.config.sondehub.active && wifi_state != WIFI_APMODE) {
|
||||||
|
time_last_update = millis() + 1000; /* force sending update */
|
||||||
|
sondehub_station_update();
|
||||||
|
|
||||||
|
// SH import: initial refresh on connect, even if configured interval is longer
|
||||||
|
shImportInterval = 5; // refresh now in 5 seconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Imitating the old non-modular code
|
||||||
|
// updateSonde is called once per second
|
||||||
|
// old code called
|
||||||
|
// each second: sondehub_reply_handler
|
||||||
|
// each second, if good decode: sondehub_send_data
|
||||||
|
// each second, if no good decode: sondehub_finish_data
|
||||||
|
void ConnSondehub::updateSonde( SondeInfo *si ) {
|
||||||
|
sondehub_reply_handler();
|
||||||
|
if(si==NULL) {
|
||||||
|
sondehub_finish_data();
|
||||||
|
} else {
|
||||||
|
sondehub_send_data(si);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ConnSondehub::updateStation( PosInfo *pi ) {
|
||||||
|
// TODO: station_update should be here and not in netsetup()
|
||||||
|
// Currently, interlnal reply_handler does this, using gpsInfo global variable instead of this pi
|
||||||
|
}
|
||||||
|
|
||||||
|
String ConnSondehub::getStatus() {
|
||||||
|
return String("");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** Code moved from RX_FSK to here ****/
|
||||||
|
|
||||||
|
// Sondehub v2 DB related codes
|
||||||
|
/*
|
||||||
|
Update station data to the sondehub v2 DB
|
||||||
|
*/
|
||||||
|
/* which_pos: 0=none, 1=fixed, 2=gps */
|
||||||
|
void ConnSondehub::sondehub_station_update() {
|
||||||
|
struct st_sondehub *conf = &sonde.config.sondehub;
|
||||||
|
#define STATION_DATA_LEN 300
|
||||||
|
char data[STATION_DATA_LEN];
|
||||||
|
char *w;
|
||||||
|
|
||||||
|
// If there is no connection to some WiFi AP, we cannot upload any data at all....
|
||||||
|
if ( wifi_state != WIFI_CONNECTED ) return;
|
||||||
|
|
||||||
|
unsigned long time_now = millis();
|
||||||
|
// time_delta will be correct, even if time_now overflows
|
||||||
|
unsigned long time_delta = time_now - time_last_update;
|
||||||
|
|
||||||
|
int chase = conf->chase;
|
||||||
|
// automatically decided if CHASE or FIXED mode is used (for config AUTO)
|
||||||
|
if (chase == SH_LOC_AUTO) {
|
||||||
|
if (posInfo.chase) chase = SH_LOC_CHASE; else chase = SH_LOC_FIXED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use 30sec update time in chase mode, 60 min in station mode.
|
||||||
|
unsigned long update_time = (chase == SH_LOC_CHASE) ? SONDEHUB_MOBILE_STATION_UPDATE_TIME : SONDEHUB_STATION_UPDATE_TIME;
|
||||||
|
|
||||||
|
// If it is not yet time to send another update. do nothing....
|
||||||
|
if ( (time_delta <= update_time) ) return;
|
||||||
|
|
||||||
|
Serial.println("sondehub_station_update()");
|
||||||
|
time_last_update = time_now;
|
||||||
|
|
||||||
|
if (!shclient.connected()) {
|
||||||
|
if (!shclient.connect(conf->host, 80)) {
|
||||||
|
Serial.println("Connection FAILED");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w = data;
|
||||||
|
// not necessary... memset(w, 0, STATION_DATA_LEN);
|
||||||
|
|
||||||
|
sprintf(w,
|
||||||
|
"{"
|
||||||
|
"\"software_name\": \"%s\","
|
||||||
|
"\"software_version\": \"%s\","
|
||||||
|
"\"uploader_callsign\": \"%s\",",
|
||||||
|
version_name, version_id, conf->callsign);
|
||||||
|
w += strlen(w);
|
||||||
|
|
||||||
|
// Only send email if provided
|
||||||
|
if (strlen(conf->email) != 0) {
|
||||||
|
sprintf(w, "\"uploader_contact_email\": \"%s\",", conf->email);
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only send antenna if provided
|
||||||
|
if (strlen(conf->antenna) != 0) {
|
||||||
|
sprintf(w, "\"uploader_antenna\": \"%s\",", conf->antenna);
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We send GPS position: (a) in CHASE mode, (b) in AUTO mode if no fixed location has been specified in config
|
||||||
|
if (chase == SH_LOC_CHASE) {
|
||||||
|
if (gpsPos.valid) {
|
||||||
|
sprintf(w,
|
||||||
|
"\"uploader_position\": [%.6f,%.6f,%d],"
|
||||||
|
"\"mobile\": true",
|
||||||
|
gpsPos.lat, gpsPos.lon, gpsPos.alt);
|
||||||
|
} else {
|
||||||
|
sprintf(w, "\"uploader_position\": [null,null,null]");
|
||||||
|
}
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
// Otherweise, in FIXED mode we send the fixed position from config (if specified)
|
||||||
|
else if (chase == SH_LOC_FIXED) {
|
||||||
|
if ((!isnan(sonde.config.rxlat)) && (!isnan(sonde.config.rxlon))) {
|
||||||
|
if (isnan(sonde.config.rxalt))
|
||||||
|
sprintf(w, "\"uploader_position\": [%.6f,%.6f,null]", sonde.config.rxlat, sonde.config.rxlon);
|
||||||
|
else
|
||||||
|
sprintf(w, "\"uploader_position\": [%.6f,%.6f,%d]", sonde.config.rxlat, sonde.config.rxlon, (int)sonde.config.rxalt);
|
||||||
|
} else {
|
||||||
|
sprintf(w, "\"uploader_position\": [null,null,null]");
|
||||||
|
}
|
||||||
|
w += strlen(w);
|
||||||
|
} else {
|
||||||
|
sprintf(w, "\"uploader_position\": [null,null,null]");
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise (in SH_LOC_NONE mode) we dont include any position info
|
||||||
|
sprintf(w, "}");
|
||||||
|
|
||||||
|
shclient.println("PUT /listeners HTTP/1.1");
|
||||||
|
shclient.print("Host: ");
|
||||||
|
shclient.println(conf->host);
|
||||||
|
shclient.println("accept: text/plain");
|
||||||
|
shclient.println("Content-Type: application/json");
|
||||||
|
shclient.print("Content-Length: ");
|
||||||
|
shclient.println(strlen(data));
|
||||||
|
shclient.println();
|
||||||
|
shclient.println(data);
|
||||||
|
Serial.println(strlen(data));
|
||||||
|
Serial.println(data);
|
||||||
|
Serial.println("Waiting for response");
|
||||||
|
// TODO: better do this asynchronously
|
||||||
|
// At least, do this safely. See Notes-on-Using-WiFiClient.txt for details
|
||||||
|
// If any of the shclient.print failed before (remote end closed connection),
|
||||||
|
// then calling client->read will cause a LoadProhibited exception
|
||||||
|
if (shclient.connected()) {
|
||||||
|
String response = shclient.readString();
|
||||||
|
Serial.println(response);
|
||||||
|
Serial.println("Response done...");
|
||||||
|
} else {
|
||||||
|
Serial.println("SH client connection closed\n");
|
||||||
|
}
|
||||||
|
//client->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Update sonde data to the sondehub v2 DB
|
||||||
|
*/
|
||||||
|
enum SHState { SH_DISCONNECTED, SH_CONNECTING, SH_CONN_IDLE, SH_CONN_APPENDING, SH_CONN_WAITACK };
|
||||||
|
|
||||||
|
SHState shState = SH_DISCONNECTED;
|
||||||
|
time_t shStart = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ConnSondehub::sondehub_reply_handler() {
|
||||||
|
// sondehub handler for tasks to be done even if no data is to be sent:
|
||||||
|
// process response messages from sondehub
|
||||||
|
// request frequency list (if active)
|
||||||
|
#define MSG_SIZE 1000
|
||||||
|
char rs_msg[MSG_SIZE];
|
||||||
|
|
||||||
|
if (shImport == 1) { // we are waiting for a reply to a sondehub frequency import request
|
||||||
|
// while we are waiting, we do nothing else with sondehub...
|
||||||
|
int res = ShFreqImport::shImportHandleReply(&shclient);
|
||||||
|
Serial.printf("ret: %d\n", res);
|
||||||
|
// res==0 means more data is expected, res==1 means complete reply received (or error)
|
||||||
|
if (res == 1) {
|
||||||
|
shImport = 2; // finished
|
||||||
|
shImportInterval = sonde.config.sondehub.fiinterval * 60;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// any reply here belongs to normal telemetry upload, lets just print it.
|
||||||
|
// and wait for a valid HTTP response
|
||||||
|
int cnt = 0;
|
||||||
|
while (shclient.available() > 0) {
|
||||||
|
// data is available from remote server, process it...
|
||||||
|
// readBytesUntil may wait for up to 1 second if enough data is not available...
|
||||||
|
// int cnt = shclient.readBytesUntil('\n', rs_msg, MSG_SIZE - 1);
|
||||||
|
int c = shclient.read();
|
||||||
|
if (c < 0) break; // should never happen in available() returned >0 right before....
|
||||||
|
rs_msg[cnt++] = c;
|
||||||
|
if (c == '\n') {
|
||||||
|
rs_msg[cnt] = 0;
|
||||||
|
Serial.println(rs_msg);
|
||||||
|
// If something that looks like a valid HTTP response is received, we are ready to send the next data item
|
||||||
|
if (shState == SH_CONN_WAITACK && cnt > 11 && strncmp(rs_msg, "HTTP/1", 6) == 0) {
|
||||||
|
shState = SH_CONN_IDLE;
|
||||||
|
}
|
||||||
|
cnt = 0;
|
||||||
|
}
|
||||||
|
if (cnt >= MSG_SIZE - 1) {
|
||||||
|
cnt = 0;
|
||||||
|
Serial.println("(overlong line from network, ignoring)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cnt > 0) {
|
||||||
|
rs_msg[cnt + 1] = 0;
|
||||||
|
Serial.println(rs_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// send import requests if needed
|
||||||
|
if (sonde.config.sondehub.fiactive) {
|
||||||
|
if (shImport == 2) {
|
||||||
|
Serial.printf("next sondehub frequncy import in %d seconds\n", shImportInterval);
|
||||||
|
shImportInterval --;
|
||||||
|
if (shImportInterval <= 0) {
|
||||||
|
shImport = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (shImport == 0) {
|
||||||
|
if (shState == SH_CONN_APPENDING || shState == SH_CONN_WAITACK)
|
||||||
|
Serial.printf("Time to request next sondehub import.... but still busy with upload request");
|
||||||
|
else
|
||||||
|
sondehub_send_fimport();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// also handle periodic station updates here...
|
||||||
|
// interval check moved to sondehub_station_update to avoid having to calculate distance in auto mode twice
|
||||||
|
if (sonde.config.sondehub.active) {
|
||||||
|
if (shState == SH_CONN_IDLE || shState == SH_DISCONNECTED ) {
|
||||||
|
// (do not set station update while a telemetry report is being sent
|
||||||
|
sondehub_station_update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnSondehub::sondehub_send_fimport() {
|
||||||
|
if (shState == SH_CONN_APPENDING || shState == SH_CONN_WAITACK) {
|
||||||
|
// Currently busy with SondeHub data upload
|
||||||
|
// So do nothing here.
|
||||||
|
// sond_fimport will be re-sent later, when shState becomes SH_CONN_IDLE
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// It's time to run, so check prerequisites
|
||||||
|
float lat = sonde.config.rxlat, lon = sonde.config.rxlon;
|
||||||
|
if (gpsPos.valid) {
|
||||||
|
lat = gpsPos.lat;
|
||||||
|
lon = gpsPos.lon;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxdist = sonde.config.sondehub.fimaxdist; // km
|
||||||
|
int maxage = sonde.config.sondehub.fimaxage * 60; // fimaxage is hours, shImportSendRequest uses minutes
|
||||||
|
int fiinterval = sonde.config.sondehub.fiinterval;
|
||||||
|
Serial.printf("shimp : %f %f %d %d %d\n", lat, lon, maxdist, maxage, shImportInterval);
|
||||||
|
if ( !isnan(lat) && !isnan(lon) && maxdist > 0 && maxage > 0 && fiinterval > 0 ) {
|
||||||
|
int res = ShFreqImport::shImportSendRequest(&shclient, lat, lon, maxdist, maxage);
|
||||||
|
if (res == 0) shImport = 1; // Request OK: wait for response
|
||||||
|
else shImport = 2; // Request failed: wait interval, then retry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// in hours.... max allowed diff UTC <-> sonde time
|
||||||
|
#define SONDEHUB_TIME_THRESHOLD (3)
|
||||||
|
void ConnSondehub::sondehub_send_data(SondeInfo * s) {
|
||||||
|
struct st_sondehub *conf = &sonde.config.sondehub;
|
||||||
|
|
||||||
|
Serial.println("sondehub_send_data()");
|
||||||
|
Serial.printf("shState = %d\n", shState);
|
||||||
|
|
||||||
|
// max age of data in JSON request (in seconds)
|
||||||
|
#define SONDEHUB_MAXAGE 15
|
||||||
|
|
||||||
|
char rs_msg[MSG_SIZE];
|
||||||
|
char *w;
|
||||||
|
struct tm ts;
|
||||||
|
// config setting M10 and M20 will both decode both types, so use the real type that was decoded
|
||||||
|
uint8_t realtype = sonde.realType(s);
|
||||||
|
|
||||||
|
// For DFM, s->d.time is data from subframe DAT8 (gps date/hh/mm), and sec is from DAT1 (gps sec/usec)
|
||||||
|
// For all others, sec should always be 0 and time the exact time in seconds
|
||||||
|
time_t t = s->d.time;
|
||||||
|
|
||||||
|
int chase = conf->chase;
|
||||||
|
// automatically decided if CHASE or FIXED mode is used (for config AUTO)
|
||||||
|
if (chase == SH_LOC_AUTO) {
|
||||||
|
if (posInfo.chase) chase = SH_LOC_CHASE; else chase = SH_LOC_FIXED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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->d.ser == 0 || s->d.validID == 0 ) return; // Don't send anything without serial number
|
||||||
|
if (((int)s->d.lat == 0) && ((int)s->d.lon == 0)) return; // Sometimes these values are zeroes. Don't send those to the sondehub
|
||||||
|
if ((int)s->d.alt > 50000) return; // If alt is too high don't send to SondeHub
|
||||||
|
// M20 data does not include #sat information
|
||||||
|
if ( realtype != STYPE_M20 && (int)s->d.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
|
||||||
|
if (!shclient.connected()) {
|
||||||
|
Serial.println("NO CONNECTION");
|
||||||
|
shState = SH_DISCONNECTED;
|
||||||
|
if (!shclient.connect(conf->host, 80)) {
|
||||||
|
Serial.println("Connection FAILED");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
shclient.Client::setTimeout(0); // does this work?
|
||||||
|
shState = SH_CONN_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( shState == SH_CONN_WAITACK ) {
|
||||||
|
Serial.println("Previous SH-frame not yet ack'ed, not sending new data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( abs(now - (time_t)s->d.time) > (3600 * SONDEHUB_TIME_THRESHOLD) ) {
|
||||||
|
Serial.printf("Sonde time %d too far from current UTC time %ld", s->d.time, now);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DFM uses UTC. Most of the other radiosondes use GPS time
|
||||||
|
// SondeHub expect datetime to be the same time sytem as the sonde transmits as time stamp
|
||||||
|
if ( realtype == STYPE_RS41 || realtype == STYPE_RS92 || realtype == STYPE_M20 ) {
|
||||||
|
t += 18; // convert back to GPS time from UTC time +18s
|
||||||
|
}
|
||||||
|
|
||||||
|
gmtime_r(&t, &ts);
|
||||||
|
|
||||||
|
memset(rs_msg, 0, MSG_SIZE);
|
||||||
|
w = rs_msg;
|
||||||
|
|
||||||
|
sprintf(w,
|
||||||
|
" {"
|
||||||
|
"\"software_name\": \"%s\","
|
||||||
|
"\"software_version\": \"%s\","
|
||||||
|
"\"uploader_callsign\": \"%s\","
|
||||||
|
"\"time_received\": \"%04d-%02d-%02dT%02d:%02d:%02d.000Z\","
|
||||||
|
"\"manufacturer\": \"%s\","
|
||||||
|
"\"serial\": \"%s\","
|
||||||
|
"\"datetime\": \"%04d-%02d-%02dT%02d:%02d:%02d.000Z\","
|
||||||
|
"\"lat\": %.5f,"
|
||||||
|
"\"lon\": %.5f,"
|
||||||
|
"\"alt\": %.5f,"
|
||||||
|
"\"frequency\": %.3f,"
|
||||||
|
"\"vel_h\": %.5f,"
|
||||||
|
"\"vel_v\": %.5f,"
|
||||||
|
"\"heading\": %.5f,"
|
||||||
|
"\"rssi\": %.1f,"
|
||||||
|
"\"frame\": %d,"
|
||||||
|
"\"type\": \"%s\",",
|
||||||
|
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[realtype], s->d.ser,
|
||||||
|
ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec,
|
||||||
|
(float)s->d.lat, (float)s->d.lon, (float)s->d.alt, (float)s->freq, (float)s->d.hs, (float)s->d.vs,
|
||||||
|
(float)s->d.dir, -((float)s->rssi / 2), s->d.vframe, sondeTypeStrSH[realtype]
|
||||||
|
);
|
||||||
|
w += strlen(w);
|
||||||
|
|
||||||
|
// Only send sats if not M20
|
||||||
|
if (realtype != STYPE_M20) {
|
||||||
|
sprintf(w, "\"sats\": %d,", (int)s->d.sats);
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if there is a subtype (DFM only) */
|
||||||
|
if ( TYPE_IS_DFM(s->type) && s->d.subtype > 0 ) {
|
||||||
|
if ( (s->d.subtype & 0xF) != DFM_UNK) {
|
||||||
|
const char *t = dfmSubtypeLong[s->d.subtype & 0xF];
|
||||||
|
sprintf(w, "\"subtype\": \"%s\",", t);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sprintf(w, "\"subtype\": \"DFMx%X\",", s->d.subtype >> 4); // Unknown subtype
|
||||||
|
}
|
||||||
|
w += strlen(w);
|
||||||
|
} else if ( s->type == STYPE_RS41 ) {
|
||||||
|
char buf[11];
|
||||||
|
if (RS41::getSubtype(buf, 11, s) == 0) {
|
||||||
|
sprintf(w, "\"subtype\": \"%s\",", buf);
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only send temp if provided
|
||||||
|
if (!isnan(s->d.temperature)) {
|
||||||
|
sprintf(w, "\"temp\": %.1f,", s->d.temperature);
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only send humidity if provided
|
||||||
|
if (!isnan(s->d.relativeHumidity)) {
|
||||||
|
sprintf(w, "\"humidity\": %.1f,", s->d.relativeHumidity);
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only send pressure if provided
|
||||||
|
if (!isnan(s->d.pressure)) {
|
||||||
|
sprintf(w, "\"pressure\": %.2f,", s->d.pressure);
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only send burst timer if RS41 and fresh within the last 51s
|
||||||
|
if ((realtype == STYPE_RS41) && (s->d.crefKT > 0) && (s->d.vframe - s->d.crefKT < 51)) {
|
||||||
|
sprintf(w, "\"burst_timer\": %d,", (int)s->d.countKT);
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only send battery if provided
|
||||||
|
if (s->d.batteryVoltage > 0) {
|
||||||
|
sprintf(w, "\"batt\": %.2f,", s->d.batteryVoltage);
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only send antenna if provided
|
||||||
|
if (strlen(conf->antenna) != 0) {
|
||||||
|
sprintf(w, "\"uploader_antenna\": \"%s\",", conf->antenna);
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We send GPS position: (a) in CHASE mode, (b) in AUTO mode if no fixed location has been specified in config
|
||||||
|
if (chase == SH_LOC_CHASE) {
|
||||||
|
if (gpsPos.valid) {
|
||||||
|
sprintf(w, "\"uploader_position\": [%.6f,%.6f,%d]", gpsPos.lat, gpsPos.lon, gpsPos.alt);
|
||||||
|
} else {
|
||||||
|
sprintf(w, "\"uploader_position\": [null,null,null]");
|
||||||
|
}
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
// Otherweise, in FIXED mode we send the fixed position from config (if specified)
|
||||||
|
else if (chase == SH_LOC_FIXED) {
|
||||||
|
if ((!isnan(sonde.config.rxlat)) && (!isnan(sonde.config.rxlon))) {
|
||||||
|
if (isnan(sonde.config.rxalt))
|
||||||
|
sprintf(w, "\"uploader_position\": [%.6f,%.6f,null]", sonde.config.rxlat, sonde.config.rxlon);
|
||||||
|
else
|
||||||
|
sprintf(w, "\"uploader_position\": [%.6f,%.6f,%d]", sonde.config.rxlat, sonde.config.rxlon, (int)sonde.config.rxalt);
|
||||||
|
} else {
|
||||||
|
sprintf(w, "\"uploader_position\": [null,null,null]");
|
||||||
|
}
|
||||||
|
w += strlen(w);
|
||||||
|
} else {
|
||||||
|
sprintf(w, "\"uploader_position\": [null,null,null]");
|
||||||
|
w += strlen(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise (in SH_LOC_NONE mode) we dont include any position info
|
||||||
|
sprintf(w, "}");
|
||||||
|
|
||||||
|
if (shState != SH_CONN_APPENDING) {
|
||||||
|
sondehub_send_header(s, &timeinfo);
|
||||||
|
sondehub_send_next(s, rs_msg, strlen(rs_msg), 1);
|
||||||
|
shState = SH_CONN_APPENDING;
|
||||||
|
shStart = now;
|
||||||
|
} else {
|
||||||
|
sondehub_send_next(s, rs_msg, strlen(rs_msg), 0);
|
||||||
|
}
|
||||||
|
if (now - shStart > SONDEHUB_MAXAGE) { // after MAXAGE seconds
|
||||||
|
sondehub_send_last();
|
||||||
|
shState = SH_CONN_WAITACK;
|
||||||
|
shStart = 0;
|
||||||
|
}
|
||||||
|
//client->println(rs_msg);
|
||||||
|
//Serial.println(rs_msg);
|
||||||
|
//String response = client->readString();
|
||||||
|
//Serial.println(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnSondehub::sondehub_finish_data() {
|
||||||
|
// 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();
|
||||||
|
shState = SH_CONN_WAITACK;
|
||||||
|
shStart = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *DAYS[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
|
||||||
|
static const char *MONTHS[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Noc", "Dec"};
|
||||||
|
|
||||||
|
void ConnSondehub::sondehub_send_header(SondeInfo * s, struct tm * now) {
|
||||||
|
struct st_sondehub *conf = &sonde.config.sondehub;
|
||||||
|
Serial.print("PUT /sondes/telemetry HTTP/1.1\r\n"
|
||||||
|
"Host: ");
|
||||||
|
Serial.println(conf->host);
|
||||||
|
Serial.print("accept: text/plain\r\n"
|
||||||
|
"Content-Type: application/json\r\n"
|
||||||
|
"Transfer-Encoding: chunked\r\n");
|
||||||
|
|
||||||
|
shclient.print("PUT /sondes/telemetry HTTP/1.1\r\n"
|
||||||
|
"Host: ");
|
||||||
|
shclient.println(conf->host);
|
||||||
|
shclient.print("accept: text/plain\r\n"
|
||||||
|
"Content-Type: application/json\r\n"
|
||||||
|
"Transfer-Encoding: chunked\r\n");
|
||||||
|
if (now) {
|
||||||
|
Serial.printf("Date: %s, %02d %s %04d %02d:%02d:%02d GMT\r\n",
|
||||||
|
DAYS[now->tm_wday], now->tm_mday, MONTHS[now->tm_mon], now->tm_year + 1900,
|
||||||
|
now->tm_hour, now->tm_min, now->tm_sec);
|
||||||
|
shclient.printf("Date: %s, %02d %s %04d %02d:%02d:%02d GMT\r\n",
|
||||||
|
DAYS[now->tm_wday], now->tm_mday, MONTHS[now->tm_mon], now->tm_year + 1900,
|
||||||
|
now->tm_hour, now->tm_min, now->tm_sec);
|
||||||
|
}
|
||||||
|
shclient.print("User-agent: ");
|
||||||
|
shclient.print(version_name);
|
||||||
|
shclient.print("/");
|
||||||
|
shclient.println(version_id);
|
||||||
|
shclient.println(""); // another cr lf as indication of end of header
|
||||||
|
}
|
||||||
|
void ConnSondehub::sondehub_send_next(SondeInfo * s, char *chunk, int chunklen, int first) {
|
||||||
|
// send next chunk of JSON request
|
||||||
|
shclient.printf("%x\r\n", chunklen + 1);
|
||||||
|
shclient.write(first ? "[" : ",", 1);
|
||||||
|
shclient.write(chunk, chunklen);
|
||||||
|
shclient.print("\r\n");
|
||||||
|
|
||||||
|
Serial.printf("%x\r\n", chunklen + 1);
|
||||||
|
Serial.write((const uint8_t *)(first ? "[" : ","), 1);
|
||||||
|
Serial.write((const uint8_t *)chunk, chunklen);
|
||||||
|
Serial.print("\r\n");
|
||||||
|
}
|
||||||
|
void ConnSondehub::sondehub_send_last() {
|
||||||
|
// last chunk. just the closing "]" of the json request
|
||||||
|
shclient.printf("1\r\n]\r\n0\r\n\r\n");
|
||||||
|
Serial.printf("1\r\n]\r\n0\r\n\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ConnSondehub connSondehub;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
#include "../features.h"
|
||||||
|
#if FEATURE_SONDEHUB
|
||||||
|
|
||||||
|
#ifndef conn_sondehub_h
|
||||||
|
#define conn_sondehub_h
|
||||||
|
|
||||||
|
#include "conn.h"
|
||||||
|
|
||||||
|
|
||||||
|
class ConnSondehub : public Conn
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/* Called once on startup */
|
||||||
|
void init();
|
||||||
|
|
||||||
|
/* Called whenever the network becomes available */
|
||||||
|
void netsetup();
|
||||||
|
|
||||||
|
/* Called approx 1x / second (maybe only if good data is available) */
|
||||||
|
void updateSonde( SondeInfo *si );
|
||||||
|
|
||||||
|
/* Called approx 1x / second* */
|
||||||
|
void updateStation( PosInfo *pi );
|
||||||
|
|
||||||
|
String getStatus();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void sondehub_station_update();
|
||||||
|
void sondehub_reply_handler();
|
||||||
|
void sondehub_send_fimport();
|
||||||
|
void sondehub_send_data(SondeInfo * s);
|
||||||
|
void sondehub_finish_data();
|
||||||
|
void sondehub_send_header(SondeInfo * s, struct tm * now);
|
||||||
|
void sondehub_send_next(SondeInfo * s, char *chunk, int chunklen, int first);
|
||||||
|
void sondehub_send_last();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern ConnSondehub connSondehub;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -34,5 +34,7 @@ public:
|
||||||
/* Called approx 1x / second* */
|
/* Called approx 1x / second* */
|
||||||
virtual void updateStation( PosInfo *pi );
|
virtual void updateStation( PosInfo *pi );
|
||||||
|
|
||||||
|
/* Called to retrieve status (used for Info in about tab) */
|
||||||
|
virtual String getStatus();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const char *version_name = "rdzTTGOsonde";
|
const char *version_name = "rdzTTGOsonde";
|
||||||
const char *version_id = "devel20240110";
|
const char *version_id = "devel20240116";
|
||||||
const int SPIFFS_MAJOR=2;
|
const int SPIFFS_MAJOR=2;
|
||||||
const int SPIFFS_MINOR=17;
|
const int SPIFFS_MINOR=17;
|
||||||
|
|
|
@ -28,6 +28,7 @@ platform = https://github.com/platformio/platform-espressif32.git#v6.3.0
|
||||||
board = ttgo-lora32-v1
|
board = ttgo-lora32-v1
|
||||||
framework = arduino
|
framework = arduino
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
monitor_filters = esp32_exception_decoder
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${extra.lib_deps_builtin}
|
${extra.lib_deps_builtin}
|
||||||
${extra.lib_deps_external}
|
${extra.lib_deps_external}
|
||||||
|
|
Ładowanie…
Reference in New Issue