kopia lustrzana https://github.com/PiInTheSky/lora-gateway
V1.9.0 - Sondehub amateur support
rodzic
62a3a98ac4
commit
79cc2bfb7e
17
README.md
17
README.md
|
@ -65,6 +65,8 @@ Raspberry Pi OS no longer includes WiringPi, so you must install Wiring Pi from
|
||||||
MQTT
|
MQTT
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
MQTT support was added recently, and needs the following library installed::
|
||||||
|
|
||||||
cd ~
|
cd ~
|
||||||
mkdir MQTTClients
|
mkdir MQTTClients
|
||||||
cd MQTTClients
|
cd MQTTClients
|
||||||
|
@ -91,6 +93,7 @@ The configuration is in the file gateway.txt. Example:
|
||||||
|
|
||||||
tracker=M0RPI
|
tracker=M0RPI
|
||||||
EnableHabitat=N
|
EnableHabitat=N
|
||||||
|
EnableSondehub=N
|
||||||
EnableSSDV=Y
|
EnableSSDV=Y
|
||||||
LogTelemetry=Y
|
LogTelemetry=Y
|
||||||
LogPackets=Y
|
LogPackets=Y
|
||||||
|
@ -121,6 +124,8 @@ The global options are:
|
||||||
|
|
||||||
EnableHabitat=<Y/N>. Enables uploading of telemetry packets to Habitat.
|
EnableHabitat=<Y/N>. Enables uploading of telemetry packets to Habitat.
|
||||||
|
|
||||||
|
EnableSondhub=<Y/N>. Enables uploading of telemetry packets to the amateur Sondehub system.
|
||||||
|
|
||||||
EnableSSDV=<Y/N>. Enables uploading of SSDV image packets to the SSDV server.
|
EnableSSDV=<Y/N>. Enables uploading of SSDV image packets to the SSDV server.
|
||||||
|
|
||||||
EnableHABLink=<Y/N>. Enables uploading of telemetry packets to the hab.link server.
|
EnableHABLink=<Y/N>. Enables uploading of telemetry packets to the hab.link server.
|
||||||
|
@ -175,8 +180,8 @@ and the channel-specific options are:
|
||||||
4 = Test mode not for normal use.
|
4 = Test mode not for normal use.
|
||||||
5 = (normal for calling mode) Explicit mode, Error coding 4:8, Bandwidth 41.7kHz, SF 11, Low data rate optimize off
|
5 = (normal for calling mode) Explicit mode, Error coding 4:8, Bandwidth 41.7kHz, SF 11, Low data rate optimize off
|
||||||
|
|
||||||
SF_<n>=<Spreading Factor> e.g. SF_0=7
|
SF_<n>=<Spreading Factor> e.g. SF_0=7
|
||||||
|
|
||||||
Bandwidth_<n>=<Bandwidth>. e.g. Bandwidth_0=41K7. Options are 7K8, 10K4, 15K6, 20K8, 31K25, 41K7, 62K5, 125K, 250K, 500K
|
Bandwidth_<n>=<Bandwidth>. e.g. Bandwidth_0=41K7. Options are 7K8, 10K4, 15K6, 20K8, 31K25, 41K7, 62K5, 125K, 250K, 500K
|
||||||
|
|
||||||
Implicit_<n>=<Y/N>. e.g. Implicit_0=Y
|
Implicit_<n>=<Y/N>. e.g. Implicit_0=Y
|
||||||
|
@ -290,11 +295,15 @@ Many thanks to David Brooke for coding this feature and the AFC.
|
||||||
Change History
|
Change History
|
||||||
==============
|
==============
|
||||||
|
|
||||||
16/02/2022 - V1.8.46
|
## 04/09/2022 - V1.9.0
|
||||||
|
|
||||||
|
Added support for uploading telemetry and listener details to the amateur Sondehub system.
|
||||||
|
|
||||||
|
## 16/02/2022 - V1.8.46
|
||||||
|
|
||||||
Added flexible MQTT topic - $GATEWAY$ gets replaced by gateway callsign; $PAYLOAD$ gets replaced by payload callsign
|
Added flexible MQTT topic - $GATEWAY$ gets replaced by gateway callsign; $PAYLOAD$ gets replaced by payload callsign
|
||||||
|
|
||||||
14/02/2022 - V1.8.45
|
## 14/02/2022 - V1.8.45
|
||||||
|
|
||||||
Added MQTT support (coded by David Johnson G4DPZ)
|
Added MQTT support (coded by David Johnson G4DPZ)
|
||||||
|
|
||||||
|
|
36
gateway.c
36
gateway.c
|
@ -33,6 +33,7 @@
|
||||||
#include "ssdv.h"
|
#include "ssdv.h"
|
||||||
#include "ftp.h"
|
#include "ftp.h"
|
||||||
#include "habitat.h"
|
#include "habitat.h"
|
||||||
|
#include "sondehub.h"
|
||||||
#include "mqtt.h"
|
#include "mqtt.h"
|
||||||
#include "hablink.h"
|
#include "hablink.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
@ -47,7 +48,7 @@
|
||||||
#include "udpclient.h"
|
#include "udpclient.h"
|
||||||
#include "lifo_buffer.h"
|
#include "lifo_buffer.h"
|
||||||
|
|
||||||
#define VERSION "V1.8.46"
|
#define VERSION "V1.9.0"
|
||||||
bool run = TRUE;
|
bool run = TRUE;
|
||||||
|
|
||||||
// RFM98
|
// RFM98
|
||||||
|
@ -1155,6 +1156,11 @@ int ProcessTelemetryMessage(int Channel, received_t *Received)
|
||||||
SetHablinkSentence(startmessage);
|
SetHablinkSentence(startmessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Config.EnableSondehub)
|
||||||
|
{
|
||||||
|
SetSondehubSentence(Channel, startmessage);
|
||||||
|
}
|
||||||
|
|
||||||
tm = localtime( &Received->Metadata.Timestamp );
|
tm = localtime( &Received->Metadata.Timestamp );
|
||||||
LogMessage("%02d:%02d:%02d Ch%d: %s%s\n", tm->tm_hour, tm->tm_min, tm->tm_sec, Channel, startmessage, Repeated ? " (repeated)" : "");
|
LogMessage("%02d:%02d:%02d Ch%d: %s%s\n", tm->tm_hour, tm->tm_min, tm->tm_sec, Channel, startmessage, Repeated ? " (repeated)" : "");
|
||||||
|
|
||||||
|
@ -2009,6 +2015,7 @@ void LoadConfigFile(void)
|
||||||
Config.InternetLED = -1;
|
Config.InternetLED = -1;
|
||||||
Config.LoRaDevices[0].ActivityLED = -1;
|
Config.LoRaDevices[0].ActivityLED = -1;
|
||||||
Config.LoRaDevices[1].ActivityLED = -1;
|
Config.LoRaDevices[1].ActivityLED = -1;
|
||||||
|
strcpy(Config.radio, "Uputronics LoRa HAT");
|
||||||
|
|
||||||
// Default pin allocations
|
// Default pin allocations
|
||||||
Config.LoRaDevices[0].DIO0 = 6;
|
Config.LoRaDevices[0].DIO0 = 6;
|
||||||
|
@ -2040,6 +2047,7 @@ void LoadConfigFile(void)
|
||||||
RegisterConfigBoolean(MainSection, -1, "EnableHabitat", &Config.EnableHabitat, NULL);
|
RegisterConfigBoolean(MainSection, -1, "EnableHabitat", &Config.EnableHabitat, NULL);
|
||||||
RegisterConfigBoolean(MainSection, -1, "EnableSSDV", &Config.EnableSSDV, NULL);
|
RegisterConfigBoolean(MainSection, -1, "EnableSSDV", &Config.EnableSSDV, NULL);
|
||||||
RegisterConfigBoolean(MainSection, -1, "EnableHablink", &Config.EnableHablink, NULL);
|
RegisterConfigBoolean(MainSection, -1, "EnableHablink", &Config.EnableHablink, NULL);
|
||||||
|
RegisterConfigBoolean(MainSection, -1, "EnableSondehub", &Config.EnableSondehub, NULL);
|
||||||
|
|
||||||
RegisterConfigString(MainSection, -1, "HablinkAddress", Config.HablinkAddress, sizeof(Config.HablinkAddress), NULL);
|
RegisterConfigString(MainSection, -1, "HablinkAddress", Config.HablinkAddress, sizeof(Config.HablinkAddress), NULL);
|
||||||
|
|
||||||
|
@ -2109,6 +2117,7 @@ void LoadConfigFile(void)
|
||||||
// Listener
|
// Listener
|
||||||
RegisterConfigDouble(MainSection, -1, "Latitude", &Config.latitude, NULL);
|
RegisterConfigDouble(MainSection, -1, "Latitude", &Config.latitude, NULL);
|
||||||
RegisterConfigDouble(MainSection, -1, "Longitude", &Config.longitude, NULL);
|
RegisterConfigDouble(MainSection, -1, "Longitude", &Config.longitude, NULL);
|
||||||
|
RegisterConfigDouble(MainSection, -1, "Altitude", &Config.altitude, NULL);
|
||||||
RegisterConfigString(MainSection, -1, "radio", Config.radio, sizeof(Config.radio), NULL);
|
RegisterConfigString(MainSection, -1, "radio", Config.radio, sizeof(Config.radio), NULL);
|
||||||
RegisterConfigString(MainSection, -1, "antenna", Config.antenna, sizeof(Config.antenna), NULL);
|
RegisterConfigString(MainSection, -1, "antenna", Config.antenna, sizeof(Config.antenna), NULL);
|
||||||
|
|
||||||
|
@ -2635,7 +2644,7 @@ int main( int argc, char **argv )
|
||||||
int ch;
|
int ch;
|
||||||
int LoopPeriod, MSPerLoop;
|
int LoopPeriod, MSPerLoop;
|
||||||
int Channel;
|
int Channel;
|
||||||
pthread_t SSDVThread, FTPThread, NetworkThread, HabitatThread, HablinkThread, ServerThread, TelnetThread, ListenerThread, DataportThread, ChatportThread, MQTTThread;
|
pthread_t SSDVThread, FTPThread, NetworkThread, HabitatThread, HablinkThread, SondehubThread, ServerThread, TelnetThread, ListenerThread, DataportThread, ChatportThread, MQTTThread;
|
||||||
struct TServerInfo JSONInfo, TelnetInfo, DataportInfo, ChatportInfo;
|
struct TServerInfo JSONInfo, TelnetInfo, DataportInfo, ChatportInfo;
|
||||||
|
|
||||||
atexit(bye);
|
atexit(bye);
|
||||||
|
@ -2735,21 +2744,21 @@ int main( int argc, char **argv )
|
||||||
if (Config.EnableMQTT)
|
if (Config.EnableMQTT)
|
||||||
{
|
{
|
||||||
lifo_buffer_init(&MQTT_Upload_Buffer, 1024);
|
lifo_buffer_init(&MQTT_Upload_Buffer, 1024);
|
||||||
mqtt_connect_t *mqttConnection = malloc(sizeof *mqttConnection);
|
mqtt_connect_t *mqttConnection = malloc(sizeof *mqttConnection);
|
||||||
|
|
||||||
strcpy(mqttConnection->host, Config.MQTTHost);
|
strcpy(mqttConnection->host, Config.MQTTHost);
|
||||||
strcpy(mqttConnection->port, Config.MQTTPort);
|
strcpy(mqttConnection->port, Config.MQTTPort);
|
||||||
strcpy(mqttConnection->user, Config.MQTTUser);
|
strcpy(mqttConnection->user, Config.MQTTUser);
|
||||||
strcpy(mqttConnection->pass, Config.MQTTPass);
|
strcpy(mqttConnection->pass, Config.MQTTPass);
|
||||||
strcpy(mqttConnection->topic, Config.MQTTTopic);
|
strcpy(mqttConnection->topic, Config.MQTTTopic);
|
||||||
strcpy(mqttConnection->clientId, Config.MQTTClient);
|
strcpy(mqttConnection->clientId, Config.MQTTClient);
|
||||||
|
|
||||||
if ( pthread_create (&MQTTThread, NULL, MQTTLoop, mqttConnection))
|
if ( pthread_create (&MQTTThread, NULL, MQTTLoop, mqttConnection))
|
||||||
{
|
{
|
||||||
fprintf( stderr, "Error creating MQTT thread\n" );
|
fprintf( stderr, "Error creating MQTT thread\n" );
|
||||||
free(mqttConnection);
|
free(mqttConnection);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.EnableHablink && Config.HablinkAddress[0])
|
if (Config.EnableHablink && Config.HablinkAddress[0])
|
||||||
|
@ -2761,6 +2770,15 @@ int main( int argc, char **argv )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Config.EnableSondehub)
|
||||||
|
{
|
||||||
|
if (pthread_create (&SondehubThread, NULL, SondehubLoop, NULL))
|
||||||
|
{
|
||||||
|
fprintf( stderr, "Error creating Sondehub thread\n" );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Config.ServerPort > 0)
|
if (Config.ServerPort > 0)
|
||||||
{
|
{
|
||||||
JSONInfo.Port = Config.ServerPort;
|
JSONInfo.Port = Config.ServerPort;
|
||||||
|
|
3
global.h
3
global.h
|
@ -110,11 +110,12 @@ struct TLoRaDevice
|
||||||
struct TConfig
|
struct TConfig
|
||||||
{
|
{
|
||||||
char Tracker[16]; // Callsign or name of receiver
|
char Tracker[16]; // Callsign or name of receiver
|
||||||
double latitude, longitude; // Receiver's location
|
double latitude, longitude, altitude; // Receiver's location
|
||||||
|
|
||||||
int EnableHabitat;
|
int EnableHabitat;
|
||||||
int EnableSSDV;
|
int EnableSSDV;
|
||||||
int EnableHablink;
|
int EnableHablink;
|
||||||
|
int EnableSondehub;
|
||||||
char HablinkAddress[32];
|
char HablinkAddress[32];
|
||||||
int EnableTelemetryLogging;
|
int EnableTelemetryLogging;
|
||||||
int EnablePacketLogging;
|
int EnablePacketLogging;
|
||||||
|
|
|
@ -0,0 +1,261 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h> // Standard input/output definitions
|
||||||
|
#include <string.h> // String function definitions
|
||||||
|
#include <unistd.h> // UNIX standard function definitions
|
||||||
|
#include <fcntl.h> // File control definitions
|
||||||
|
#include <errno.h> // Error number definitions
|
||||||
|
#include <termios.h> // POSIX terminal control definitions
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <wiringPi.h>
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "gateway.h"
|
||||||
|
#include "sondehub.h"
|
||||||
|
|
||||||
|
struct TPayload SondehubPayloads[2];
|
||||||
|
|
||||||
|
void SetSondehubSentence(int Channel, char *tmp)
|
||||||
|
{
|
||||||
|
sscanf(tmp + 2, "%31[^,],%u,%8[^,],%lf,%lf,%d",
|
||||||
|
SondehubPayloads[Channel].Payload,
|
||||||
|
&SondehubPayloads[Channel].Counter,
|
||||||
|
SondehubPayloads[Channel].Time,
|
||||||
|
&SondehubPayloads[Channel].Latitude,
|
||||||
|
&SondehubPayloads[Channel].Longitude,
|
||||||
|
&SondehubPayloads[Channel].Altitude);
|
||||||
|
|
||||||
|
// LogMessage("Sondehub: %s,%d,%s,%.5lf,%.5lf,%d\n",
|
||||||
|
// SondehubPayloads[Channel].Payload,
|
||||||
|
// SondehubPayloads[Channel].Counter,
|
||||||
|
// SondehubPayloads[Channel].Time,
|
||||||
|
// SondehubPayloads[Channel].Latitude,
|
||||||
|
// SondehubPayloads[Channel].Longitude,
|
||||||
|
// SondehubPayloads[Channel].Altitude);
|
||||||
|
|
||||||
|
SondehubPayloads[Channel].InUse = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sondehub_write_data( void *buffer, size_t size, size_t nmemb, void *userp )
|
||||||
|
{
|
||||||
|
// LogMessage("%s\n", (char *)buffer);
|
||||||
|
return size * nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UploadJSONToServer(char *url, char *json)
|
||||||
|
{
|
||||||
|
CURL *curl;
|
||||||
|
CURLcode res;
|
||||||
|
char curl_error[CURL_ERROR_SIZE];
|
||||||
|
|
||||||
|
/* get a curl handle */
|
||||||
|
curl = curl_easy_init( );
|
||||||
|
if ( curl )
|
||||||
|
{
|
||||||
|
bool result;
|
||||||
|
struct curl_slist *headers = NULL;
|
||||||
|
int retries;
|
||||||
|
long int http_resp;
|
||||||
|
|
||||||
|
// So that the response to the curl PUT doesn't mess up my finely crafted display!
|
||||||
|
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, sondehub_write_data );
|
||||||
|
|
||||||
|
// Set the timeout
|
||||||
|
curl_easy_setopt( curl, CURLOPT_TIMEOUT, 15 );
|
||||||
|
|
||||||
|
// RJH capture http errors and report
|
||||||
|
// curl_easy_setopt( curl, CURLOPT_FAILONERROR, 1 );
|
||||||
|
curl_easy_setopt( curl, CURLOPT_ERRORBUFFER, curl_error );
|
||||||
|
|
||||||
|
// Avoid curl library bug that happens if above timeout occurs (sigh)
|
||||||
|
curl_easy_setopt( curl, CURLOPT_NOSIGNAL, 1 );
|
||||||
|
|
||||||
|
// Set the headers
|
||||||
|
headers = NULL;
|
||||||
|
headers = curl_slist_append(headers, "Accept: application/json");
|
||||||
|
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||||
|
headers = curl_slist_append(headers, "charsets: utf-8" );
|
||||||
|
|
||||||
|
// PUT https://api.v2.sondehub.org/amateur/telemetry with content-type application/json
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json);
|
||||||
|
|
||||||
|
retries = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Perform the request, res will get the return code
|
||||||
|
res = curl_easy_perform( curl );
|
||||||
|
|
||||||
|
// Check for errors
|
||||||
|
if ( res == CURLE_OK )
|
||||||
|
{
|
||||||
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp);
|
||||||
|
if (http_resp == 200)
|
||||||
|
{
|
||||||
|
// LogMessage("Saved OK to sondehub\n");
|
||||||
|
// Everything performing nominally (even if we didn't successfully insert this time)
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogMessage("Unexpected HTTP response %ld for URL '%s'\n", http_resp, url);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
http_resp = 0;
|
||||||
|
LogMessage("Failed for URL '%s'\n", url);
|
||||||
|
LogMessage("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||||
|
LogMessage("error: %s\n", curl_error);
|
||||||
|
// Likely a network error, so return false to requeue
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
} while ((!result) && (++retries < 5));
|
||||||
|
|
||||||
|
// always cleanup
|
||||||
|
curl_slist_free_all( headers );
|
||||||
|
curl_easy_cleanup( curl );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* CURL error, return false so we requeue */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int UploadSondehubPosition(int Channel)
|
||||||
|
{
|
||||||
|
char url[200];
|
||||||
|
char json[1000], now[32], doc_time[32];
|
||||||
|
time_t rawtime;
|
||||||
|
struct tm *tm, *doc_tm;
|
||||||
|
|
||||||
|
// Get formatted timestamp for now
|
||||||
|
time( &rawtime );
|
||||||
|
tm = gmtime( &rawtime );
|
||||||
|
strftime( now, sizeof( now ), "%Y-%0m-%0dT%H:%M:%SZ", tm );
|
||||||
|
|
||||||
|
// Get formatted timestamp for doc timestamp
|
||||||
|
doc_tm = gmtime( &rawtime );
|
||||||
|
strftime(doc_time, sizeof( doc_time ), "%Y-%0m-%0dT%H:%M:%SZ", doc_tm);
|
||||||
|
|
||||||
|
// Create json as required by sondehub-amateur
|
||||||
|
sprintf(json, "[{\"software_name\": \"LoRa Gateway\"," // Fixed software name
|
||||||
|
"\"software_version\": \"%s\"," // Version
|
||||||
|
"\"uploader_callsign\": \"%s\"," // User callsign
|
||||||
|
"\"time_received\": \"%s\"," // UTC
|
||||||
|
"\"payload_callsign\": \"%s\"," // Payload callsign
|
||||||
|
"\"datetime\":\"%s\"," // UTC from payload
|
||||||
|
"\"lat\": %.5lf," // Latitude
|
||||||
|
"\"lon\": %.5lf," // Longitude
|
||||||
|
"\"alt\": %.d," // Altitude
|
||||||
|
"\"frequency\": %.4lf," // Frequency
|
||||||
|
"\"modulation\": \"LoRa\"," // Modulation
|
||||||
|
// DoubleToString('snr', SNR, HasSNR) +
|
||||||
|
// DoubleToString('rssi', PacketRSSI, HasPacketRSSI) +
|
||||||
|
"\"uploader_position\": ["
|
||||||
|
" %.3lf," // Listener Latitude
|
||||||
|
" %.3lf," // Listener Longitude
|
||||||
|
" %.0lf" // Listener Altitude
|
||||||
|
"],"
|
||||||
|
"\"uploader_antenna\": \"%s\""
|
||||||
|
"}]",
|
||||||
|
Config.Version, Config.Tracker, now,
|
||||||
|
SondehubPayloads[Channel].Payload, doc_time,
|
||||||
|
SondehubPayloads[Channel].Latitude, SondehubPayloads[Channel].Longitude, SondehubPayloads[Channel].Altitude,
|
||||||
|
Config.LoRaDevices[Channel].Frequency + Config.LoRaDevices[Channel].FrequencyOffset,
|
||||||
|
Config.latitude, Config.longitude, Config.altitude, Config.antenna);
|
||||||
|
|
||||||
|
// Set the URL that is about to receive our PUT
|
||||||
|
strcpy(url, "https://api.v2.sondehub.org/amateur/telemetry");
|
||||||
|
|
||||||
|
return UploadJSONToServer(url, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
int UploadListenerToSondehub(void)
|
||||||
|
{
|
||||||
|
char url[200];
|
||||||
|
char json[1000], now[32], doc_time[32];
|
||||||
|
time_t rawtime;
|
||||||
|
struct tm *tm, *doc_tm;
|
||||||
|
|
||||||
|
// Get formatted timestamp for now
|
||||||
|
time( &rawtime );
|
||||||
|
tm = gmtime( &rawtime );
|
||||||
|
strftime( now, sizeof( now ), "%Y-%0m-%0dT%H:%M:%SZ", tm );
|
||||||
|
|
||||||
|
// Get formatted timestamp for doc timestamp
|
||||||
|
doc_tm = gmtime( &rawtime );
|
||||||
|
strftime(doc_time, sizeof( doc_time ), "%Y-%0m-%0dT%H:%M:%SZ", doc_tm);
|
||||||
|
|
||||||
|
// Create json as required by sondehub-amateur
|
||||||
|
sprintf(json, "{\"software_name\": \"LoRa Gateway\"," // Fixed software name
|
||||||
|
"\"software_version\": \"%s\"," // Version
|
||||||
|
"\"uploader_callsign\": \"%s\"," // User callsign
|
||||||
|
"\"uploader_position\": ["
|
||||||
|
" %.3lf," // Listener Latitude
|
||||||
|
" %.3lf," // Listener Longitude
|
||||||
|
" %.0lf" // Listener Altitude
|
||||||
|
"],"
|
||||||
|
"\"uploader_radio\": \"%s\","
|
||||||
|
"\"uploader_antenna\": \"%s\""
|
||||||
|
"}",
|
||||||
|
Config.Version, Config.Tracker,
|
||||||
|
Config.latitude, Config.longitude, Config.altitude,
|
||||||
|
Config.radio, Config.antenna);
|
||||||
|
|
||||||
|
strcpy(url, "https://api.v2.sondehub.org/amateur/listeners");
|
||||||
|
|
||||||
|
return UploadJSONToServer(url, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *SondehubLoop( void *vars )
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
static long ListenerCountdown = 0;
|
||||||
|
int Channel;
|
||||||
|
|
||||||
|
for (Channel=0; Channel<=1; Channel++)
|
||||||
|
{
|
||||||
|
if (SondehubPayloads[Channel].InUse)
|
||||||
|
{
|
||||||
|
if (UploadSondehubPosition(Channel))
|
||||||
|
{
|
||||||
|
SondehubPayloads[Channel].InUse = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--ListenerCountdown <= 0)
|
||||||
|
{
|
||||||
|
if (UploadListenerToSondehub())
|
||||||
|
{
|
||||||
|
LogMessage("Uploaded listener info to sondhub");
|
||||||
|
ListenerCountdown = 216000; // Every 6 hours
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogMessage("Failed to upload listener info to Sondehub/amateur");
|
||||||
|
ListenerCountdown = 600; // Try again in 1 minute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(100000);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
void *SondehubLoop( void *some_void_ptr );
|
||||||
|
void SetSondehubSentence(int Channel, char *tmp);
|
Ładowanie…
Reference in New Issue