Merge remote-tracking branch 'oh3bsg/sondehub' into sondehub

pull/80/head
Hansi, dl9rdz 2021-05-23 11:07:11 +02:00
commit 664a8b3550
15 zmienionych plików z 305 dodań i 47 usunięć

Wyświetl plik

@ -2,6 +2,7 @@
#include <WiFi.h>
#include <WiFiUdp.h>
//#include <WiFiClientSecure.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>
//#include <U8x8lib.h>
@ -11,7 +12,6 @@
#include <ESPmDNS.h>
#include <MicroNMEA.h>
#include <Ticker.h>
#include <SX1278FSK.h>
#include <Sonde.h>
#include <Display.h>
@ -47,6 +47,9 @@ String *updateBin = &updateBinM;
boolean connected = false;
WiFiUDP udp;
WiFiClient client;
//WiFiClient rsclient; // Radiosondy client
//WiFiClientSecure shclient; // Sondehub v2
WiFiClient shclient; // Sondehub v2
// KISS over TCP for communicating with APRSdroid
WiFiServer tncserver(14580);
@ -582,6 +585,17 @@ struct st_configitems config_list[] = {
{"gps_txd", "GPS TXD pin (not really needed)", 0, &sonde.config.gps_txd},
{"mdnsname", "mDNS name", 14, &sonde.config.mdnsname},
/* Sondehub v2 settings */
{"", "Sondehub v2 settings", -5, NULL},
{"sondehub.active", "Sondehub reporting active", 0, &sonde.config.sondehub.active},
{"sondehub.host", "Sondehub host", 63, &sonde.config.sondehub.host},
{"sondehub.callsign", "Callsign", 63, &sonde.config.sondehub.callsign},
{"sondehub.lat", "Latitude", 19, &sonde.config.sondehub.lat},
{"sondehub.lon", "Longitude", 19, &sonde.config.sondehub.lon},
{"sondehub.alt", "Altitude", 19, &sonde.config.sondehub.alt},
{"sondehub.antenna", "Antenna", 63, &sonde.config.sondehub.antenna},
{"sondehub.email", "Sondehub email", 63, &sonde.config.sondehub.email},
};
const static int N_CONFIG = (sizeof(config_list) / sizeof(struct st_configitems));
@ -1036,8 +1050,10 @@ void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventT
if (type == WS_EVT_CONNECT) {
Serial.println("Websocket client connection received");
client->text("Hello from ESP32 Server");
//globalClient = client;
} else if (type == WS_EVT_DISCONNECT) {
Serial.println("Client disconnected");
globalClient = NULL;
}
}
#endif
@ -1056,6 +1072,11 @@ void SetupAsyncServer() {
request->send(SPIFFS, "/index.html", String(), false, processor);
});
/*
server.on("/spectrum", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/ws.html", "text/html");
});
*/
server.on("/test.html", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(SPIFFS, "/test.html", String(), false, processor);
});
@ -2109,14 +2130,17 @@ void loopDecoder() {
tncclient.write(raw, rawlen);
}
}
if (sonde.config.sondehub.active) {
sondehub_send_data(&shclient, s, &sonde.config.sondehub);
}
}
// send to MQTT if enabled
if (connected && mqttEnabled) {
Serial.println("Sending sonde info via MQTT");
mqttclient.publishPacket(s);
}
}
//}
// always send data, even if not valid....
if (rdzclient.connected()) {
Serial.println("Sending position via TCP as rdzJSON");
@ -2244,6 +2268,13 @@ void loopSpectrum() {
scanner.scan();
scanner.plotResult();
/*
if(globalClient != NULL && globalClient->status() == WS_CONNECTED){
String randomNumber = String(random(0,20));
globalClient->text(randomNumber);
}
*/
if (sonde.config.spectrum > 0) {
int remaining = sonde.config.spectrum - (millis() - specTimer) / 1000;
@ -2287,6 +2318,9 @@ String translateEncryptionType(wifi_auth_mode_t encryptionType) {
}
}
enum t_wifi_state { WIFI_DISABLED, WIFI_SCAN, WIFI_CONNECT, WIFI_CONNECTED, WIFI_APMODE };
static t_wifi_state wifi_state = WIFI_DISABLED;
void enableNetwork(bool enable) {
if (enable) {
@ -2306,6 +2340,10 @@ void enableNetwork(bool enable) {
mqttclient.init(sonde.config.mqtt.host, sonde.config.mqtt.port, sonde.config.mqtt.id, sonde.config.mqtt.username, sonde.config.mqtt.password, sonde.config.mqtt.prefix);
}
if (sonde.config.sondehub.active && wifi_state != WIFI_APMODE) {
sondehub_station_update(&shclient, &sonde.config.sondehub);
}
connected = true;
} else {
MDNS.end();
@ -2313,11 +2351,6 @@ void enableNetwork(bool enable) {
}
}
enum t_wifi_state { WIFI_DISABLED, WIFI_SCAN, WIFI_CONNECT, WIFI_CONNECTED, WIFI_APMODE };
static t_wifi_state wifi_state = WIFI_DISABLED;
// Events used only for debug output right now
void WiFiEvent(WiFiEvent_t event)
{
@ -2871,3 +2904,165 @@ void loop() {
}
}
// Sondehub v2 DB related codes
/*
* Update station data to the sondehub v2 DB
*/
void sondehub_station_update(WiFiClient *client, struct st_sondehub *conf) {
char data[300];
Serial.println("sondehub_station_update()");
if (!client->connected()) {
if (!client->connect(conf->host, 80)) {
Serial.println("Connection FAILED");
return;
}
}
client->println("PUT /listeners 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: ");
sprintf(data,
"{"
"\"software_name\": \"%s\","
"\"software_version\": \"%s\","
"\"uploader_callsign\": \"%s\","
"\"uploader_contact_email\": \"%s\","
"\"uploader_position\": [%s,%s,%s],"
"\"uploader_antenna\": \"%s\""
"}",
version_name, version_id, conf->callsign, conf->email, conf->lat, conf->lon, conf->alt, conf->antenna);
client->println(strlen(data));
client->println();
client->println(data);
Serial.println(strlen(data));
Serial.println(data);
String response = client->readString();
Serial.println(response);
client->stop();
}
/*
* Update sonde data to the sondehub v2 DB
*/
void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *conf) {
Serial.println("sondehub_send_data()");
#define MSG_SIZE 550
char rs_msg[MSG_SIZE];
char *w;
struct tm ts;
time_t t = s->time;
if (String(s->ser) == "") 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
if ((int)s->sats < 4) return; // If not enough sats don't send to SondeHub
if (String(sondeTypeStr[s->type]) == "RS41" || String(sondeTypeStr[s->type]) == "RS92" || String(sondeTypeStr[s->type]) == "M10" || String(sondeTypeStr[s->type]) == "M20") {
t += 18; // convert back to GPS time from UTC time +18s
}
ts = *gmtime(&t);
memset(rs_msg, 0, MSG_SIZE);
w=rs_msg;
if (((int)s->temperature != 0) && ((int)s->relativeHumidity != 0)) {
sprintf(w,
"[ {"
"\"software_name\": \"%s\","
"\"software_version\": \"%s\","
"\"uploader_callsign\": \"%s\","
"\"time_received\": \"%04d-%02d-%02dT%02d:%02d:%02d.000Z\","
"\"manufacturer\": \"%s\","
"\"type\": \"%s\","
"\"serial\": \"%s\","
"\"frame\": %d,"
"\"datetime\": \"%04d-%02d-%02dT%02d:%02d:%02d.000Z\","
"\"lat\": %.6f,"
"\"lon\": %.6f,"
"\"alt\": %.2f,"
"\"frequency\": %.3f,"
"\"vel_h\": %.1f,"
"\"vel_v\": %.1f,"
"\"heading\": %.1f,"
"\"sats\": %d,"
"\"rssi\": %.1f,"
"\"temp\": %.2f,"
"\"humidity\": %.2f,"
"\"uploader_position\": [ %s, %s, %s ],"
"\"uploader_antenna\": \"%s\""
"}]",
version_name, version_id, conf->callsign,
ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec + s->sec,
manufacturer_string[s->type], sondeTypeStr[s->type], s->ser, s->frame,
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->temperature), float(s->relativeHumidity), conf->lat, conf->lon, conf->alt, conf->antenna
);
}
else {
sprintf(w,
"[ {"
"\"software_name\": \"%s\","
"\"software_version\": \"%s\","
"\"uploader_callsign\": \"%s\","
"\"time_received\": \"%04d-%02d-%02dT%02d:%02d:%02d.000Z\","
"\"manufacturer\": \"%s\","
"\"type\": \"%s\","
"\"serial\": \"%s\","
"\"frame\": %d,"
"\"datetime\": \"%04d-%02d-%02dT%02d:%02d:%02d.000Z\","
"\"lat\": %.6f,"
"\"lon\": %.6f,"
"\"alt\": %.2f,"
"\"frequency\": %.3f,"
"\"vel_h\": %.1f,"
"\"vel_v\": %.1f,"
"\"heading\": %.1f,"
"\"sats\": %d,"
"\"rssi\": %.1f,"
"\"uploader_position\": [ %s, %s, %s ],"
"\"uploader_antenna\": \"%s\""
"}]",
version_name, version_id, conf->callsign,
ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec + s->sec,
manufacturer_string[s->type], sondeTypeStr[s->type], s->ser, s->frame,
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), conf->lat, conf->lon, conf->alt, conf->antenna
);
}
if (!client->connected()) {
Serial.println("NO CONNECTION");
if (!client->connect(conf->host, 80)) {
Serial.println("Connection FAILED");
return;
}
}
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(w));
client->println();
client->println(w);
Serial.println(w);
String response = client->readString();
Serial.println(response);
}
// End of sondehub v2 related codes

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -91,7 +91,7 @@ ephftp=www.ngs.noaa.gov/cors/rinex/
#-------------------------------#
# local use only, do not feed to public services
# data not sanitized / quality checked, outliers not filtered out
axudp.active=1
axudp.active=0
axudp.host=192.168.42.20
axudp.port=9002
axudp.symbol=/O
@ -112,12 +112,24 @@ tcp.idformat=0
#-------------------------------#
# data not sanitized / quality checked, outliers not filtered out
mqtt.active=0
mqtt.id=rdz_sonde_server
mqtt.host=
mqtt.port=1883
mqtt.id=BSG_MQTT
mqtt.ip=192.168.1.5
mqtt.port=1884
mqtt.username=
mqtt.password=
mqtt.prefix=rdz_sonde_server/
#-------------------------------#
# Sondehub v2 settings
#-------------------------------#
# Sondehub v2 DB settings
sondehub.active=1
sondehub.host=api.v2.sondehub.org
sondehub.callsign=CHANGEME_BSG_TTGO
sondehub.lat=null
sondehub.lon=null
sondehub.alt=null
sondehub.antenna=
sondehub.email=
#-------------------------------#
# EOF
#-------------------------------#

Wyświetl plik

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>rdzTTGOsonde Server</title>
<title>BSGSonde Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="UTF-8">
<link rel="icon" href="data:,">
@ -9,7 +9,12 @@
</head>
<body>
<div class="wrapper"><div class="header">
<h1>RDZSonde Server</h1>
<h2>BSGSonde Server</h2>
<!--
<p>GPIO state: <strong> %STATE%</strong></p>
<p><a href="/on"><button class="button">ON</button></a></p>
<p><a href="/off"><button class="button button2">OFF</button></a></p>
-->
<div class="tab">
<button class="tablinks" onclick="selTab(event,'QRG')" id="defaultTab">QRG</button>

Wyświetl plik

@ -1,4 +1,2 @@
RDZsonde
RDZsonde
DinoGast
Schokolade
oh3bsg
oh3bsg

Wyświetl plik

@ -1,23 +1,16 @@
# Frequency in Mhz (format nnn.nnn)
# Type (4=RS41, 6=DFM normal, DFM-06, 9=DFM inverted, DFM-09)
#
402.300 4 + Greifswald
402.500 4 - Schleswig
402.700 4 + HH-Sasel
403.000 4 - DeBilt
404.100 4 + Norderney
404.300 4 - Schleswig_2
404.500 4 - Meppen
404.700 4 - Greifswald_2
405.100 4 - Lindenberg
405.700 4 + Bergen
405.900 4 + Bergen_2
405.100 4 + Meppen_2
405.300 4 - Essen
403.330 9 - TrUebPl
403.450 9 - TrUebPl
403.470 9 - TrUebPl
403.850 9 - TrUebPl
403.870 9 - TrUebPl
403.890 9 - TrUebPl
403.000 4 + Jokioinen
405.300 4 + Sundsvall
404.000 4 + Tallinn
401.000 4 + Niinisalo
401.800 4 + Vaisala
402.000 4 + Vaisala
402.700 4 + Vaisala
402.400 4 + Vaisala
403.500 4 + Katajaluoto
402.500 4 + Katajaluoto
404.000 4 + Tallinn
405.300 4 + Sundsvall
# end

Wyświetl plik

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<script type = "text/javascript">
var ws = new WebSocket("ws://192.168.1.18/ws");
ws.onopen = function() {
window.alert("Connected");
};
ws.onmessage = function(evt) {
document.getElementById("display").innerHTML = "temperature: " + evt.data + " C";
};
</script>
</head>
<body>
<div>
<p id = "display">Not connected</p>
</div>
</body>
</html>

Wyświetl plik

@ -1,4 +1,4 @@
const char *version_name = "rdzTTGOsonde";
const char *version_id = "devel20210509";
const char *version_id = "sondehub";
const int SPIFFS_MAJOR=2;
const int SPIFFS_MINOR=11;

Wyświetl plik

@ -4,7 +4,7 @@
#include "SX1278FSK.h"
#include "Sonde.h"
#define DFM_DEBUG 1
#define DFM_DEBUG 0
#if DFM_DEBUG
#define DFM_DBG(x) x

Wyświetl plik

@ -5,7 +5,7 @@
#include "rsc.h"
#include "Sonde.h"
#define RS41_DEBUG 0
#define RS41_DEBUG 1
#if RS41_DEBUG
#define RS41_DBG(x) x

Wyświetl plik

@ -9,7 +9,6 @@
#ifndef inttypes_h
#include <inttypes.h>
#endif
class Scanner
{
private:

Wyświetl plik

@ -20,6 +20,9 @@ const char *evstring[]={"NONE", "KEY1S", "KEY1D", "KEY1M", "KEY1L", "KEY2S", "KE
const char *RXstr[]={"RX_OK", "RX_TIMEOUT", "RX_ERROR", "RX_UNKNOWN"};
// Dependency to enum SondeType
const char *manufacturer_string[]={"Graw", "Graw", "Vaisala", "Vaisala", "Meteomodem", "Meteomodem", "Graw", "???"};
int fingerprintValue[]={ 17, 31, 64, 4, 55, 48, 23, 128+23, 119, 128+119, -1 };
const char *fingerprintText[]={
"TTGO T-Beam (new version 1.0), I2C not working after powerup, assuming 0.9\" OLED@21,22",
@ -371,7 +374,22 @@ void Sonde::setConfig(const char *cfg) {
strncpy(config.mqtt.password, val, 63);
} else if(strcmp(cfg,"mqtt.prefix")==0) {
strncpy(config.mqtt.prefix, val, 63);
} else if(strcmp(cfg, "sondehub.active")==0) {
config.sondehub.active = atoi(val);
} else if(strcmp(cfg, "sondehub.host")==0) {
strncpy(config.sondehub.host, val, 63);
} else if(strcmp(cfg, "sondehub.callsign")==0) {
strncpy(config.sondehub.callsign, val, 63);
} else if(strcmp(cfg, "sondehub.lat")==0) {
strncpy(config.sondehub.lat, val, 19);
} else if(strcmp(cfg, "sondehub.lon")==0) {
strncpy(config.sondehub.lon, val, 19);
} else if(strcmp(cfg, "sondehub.alt")==0) {
strncpy(config.sondehub.alt, val, 19);
} else if(strcmp(cfg, "sondehub.antenna")==0) {
strncpy(config.sondehub.antenna, val, 63);
} else if(strcmp(cfg, "sondehub.email")==0) {
strncpy(config.sondehub.email, val, 63);
} else {
Serial.printf("Invalid config option '%s'=%s \n", cfg, val);
}

Wyświetl plik

@ -58,6 +58,7 @@ enum SondeType { STYPE_DFM, STYPE_DFM09_OLD, STYPE_RS41, STYPE_RS92, STYPE_M10,
extern const char *sondeTypeStr[NSondeTypes];
extern const char *sondeTypeLongStr[NSondeTypes];
extern const char sondeTypeChar[NSondeTypes];
extern const char *manufacturer_string[NSondeTypes];
#define TYPE_IS_DFM(t) ( (t)==STYPE_DFM || (t)==STYPE_DFM09_OLD || (t)==STYPE_DFM06_OLD )
#define TYPE_IS_METEO(t) ( (t)==STYPE_M10 || (t)==STYPE_M20 )
@ -180,6 +181,17 @@ struct st_mqtt {
char prefix[64];
};
struct st_sondehub {
int active;
char host[64];
char callsign[64];
char lat[20];
char lon[20];
char alt[20];
char antenna[64];
char email[64];
};
typedef struct st_rdzconfig {
// hardware configuration
int button_pin; // PIN port number menu button (+128 for touch mode)
@ -229,6 +241,7 @@ typedef struct st_rdzconfig {
struct st_feedinfo tcpfeed; // target for APRS-IS TCP connections
struct st_kisstnc kisstnc; // target for KISS TNC (via TCP, mainly for APRSdroid)
struct st_mqtt mqtt;
struct st_sondehub sondehub;
} RDZConfig;

Wyświetl plik

@ -279,7 +279,8 @@ char *aprs_senddata(SondeInfo *s, const char *usercall, const char *sym) {
*b=0;
aprsstr_append(b, usercall);
aprsstr_append(b, ">");
const char *destcall="APZRDZ";
// const char *destcall="APZRDZ";
const char *destcall="APRARX,SONDEGATE,TCPIP,qAR,oh3bsg";
aprsstr_append(b, destcall);
// uncompressed
aprsstr_append(b, ":;");

Wyświetl plik

@ -26,11 +26,12 @@ lib_deps_external =
https://github.com/dx168b/async-mqtt-client
[env:ttgo-lora32]
;platform = espressif32
platform = https://github.com/platformio/platform-espressif32.git
board = ttgo-lora32-v1
framework = arduino
monitor_speed = 115200
lib_deps =
${extra.lib_deps_builtin}
${extra.lib_deps_external}
lib_deps =
${extra.lib_deps_builtin}
${extra.lib_deps_external}
paulstoffregen/Time@^1.6.0
lib_ignore = Time