mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 04:50:29 -04:00 
			
		
		
		
	
		
			
	
	
		
			203 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			203 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | ///////////////////////////////////////////////////////////////////////////////////
 | ||
|  | // Copyright (C) 2024 Jon Beniston, M7RCE                                        //
 | ||
|  | //                                                                               //
 | ||
|  | // This program is free software; you can redistribute it and/or modify          //
 | ||
|  | // it under the terms of the GNU General Public License as published by          //
 | ||
|  | // the Free Software Foundation as version 3 of the License, or                  //
 | ||
|  | // (at your option) any later version.                                           //
 | ||
|  | //                                                                               //
 | ||
|  | // This program is distributed in the hope that it will be useful,               //
 | ||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||
|  | // GNU General Public License V3 for more details.                               //
 | ||
|  | //                                                                               //
 | ||
|  | // You should have received a copy of the GNU General Public License             //
 | ||
|  | // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||
|  | ///////////////////////////////////////////////////////////////////////////////////
 | ||
|  | 
 | ||
|  | #include "sondehub.h"
 | ||
|  | #include "util/radiosonde.h"
 | ||
|  | 
 | ||
|  | #include <QDebug>
 | ||
|  | #include <QUrl>
 | ||
|  | #include <QUrlQuery>
 | ||
|  | #include <QNetworkReply>
 | ||
|  | #include <QJsonDocument>
 | ||
|  | #include <QJsonObject>
 | ||
|  | 
 | ||
|  | SondeHub::SondeHub() | ||
|  | { | ||
|  |     m_networkManager = new QNetworkAccessManager(); | ||
|  |     connect(m_networkManager, &QNetworkAccessManager::finished, this, &SondeHub::handleReply); | ||
|  | } | ||
|  | 
 | ||
|  | SondeHub::~SondeHub() | ||
|  | { | ||
|  |     disconnect(m_networkManager, &QNetworkAccessManager::finished, this, &SondeHub::handleReply); | ||
|  |     delete m_networkManager; | ||
|  | } | ||
|  | 
 | ||
|  | SondeHub* SondeHub::create() | ||
|  | { | ||
|  |     return new SondeHub(); | ||
|  | } | ||
|  | 
 | ||
|  | void SondeHub::upload( | ||
|  |     const QString uploaderCallsign, | ||
|  |     QDateTime timeReceived, | ||
|  |     RS41Frame *frame, | ||
|  |     const RS41Subframe *subframe, | ||
|  |     float uploaderLat, | ||
|  |     float uploaderLon, | ||
|  |     float uploaderAlt | ||
|  |     ) | ||
|  | { | ||
|  |     // Check we have required data
 | ||
|  |     if (!frame->m_statusValid || !frame->m_posValid) { | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     QJsonArray uploaderPos { | ||
|  |         uploaderLat, uploaderLon, uploaderAlt | ||
|  |     }; | ||
|  | 
 | ||
|  |     QJsonObject obj { | ||
|  |         {"software_name", "SDRangel"}, | ||
|  |         {"software_version", qApp->applicationVersion()}, | ||
|  |         {"uploader_callsign", uploaderCallsign}, | ||
|  |         {"time_received", timeReceived.toUTC().toString("yyyy-MM-ddTHH:mm:ss.zzz000Z")}, | ||
|  |         {"manufacturer", "Vaisala"}, | ||
|  |         {"type", "RS41"}, | ||
|  |         {"uploader_position", uploaderPos} | ||
|  |     }; | ||
|  | 
 | ||
|  |     if (frame->m_statusValid) | ||
|  |     { | ||
|  |         obj.insert("frame", frame->m_frameNumber); | ||
|  |         obj.insert("serial", frame->m_serial); | ||
|  |         obj.insert("batt", frame->m_batteryVoltage); | ||
|  |     } | ||
|  | 
 | ||
|  |     if (frame->m_measValid) | ||
|  |     { | ||
|  |         // Don't upload uncalibrated measurements, as there can be a significant error
 | ||
|  |         if (frame->isTemperatureCalibrated()) { | ||
|  |             obj.insert("temp", frame->getTemperatureFloat(subframe)); | ||
|  |         } | ||
|  |         if (frame->isHumidityCalibrated()) | ||
|  |         { | ||
|  |             float humidity = frame->getHumidityFloat(subframe); | ||
|  |             if (humidity != 0.0f) { | ||
|  |                 obj.insert("humidity", humidity); | ||
|  |             } | ||
|  |         } | ||
|  |         if (frame->isPressureCalibrated()) | ||
|  |         { | ||
|  |             float pressure = frame->getPressureFloat(subframe); | ||
|  |             if (pressure != 0.0f) { | ||
|  |                 obj.insert("pressure", pressure); | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     if (frame->m_gpsInfoValid) | ||
|  |     { | ||
|  |         obj.insert("datetime", frame->m_gpsDateTime.toUTC().addSecs(18).toString("yyyy-MM-ddTHH:mm:ss.zzz000Z")); // +18 adjusts UTC to GPS time
 | ||
|  |     } | ||
|  | 
 | ||
|  |     if (frame->m_posValid) | ||
|  |     { | ||
|  |         obj.insert("lat", frame->m_latitude); | ||
|  |         obj.insert("lon", frame->m_longitude); | ||
|  |         obj.insert("alt", frame->m_height); | ||
|  |         obj.insert("vel_h", frame->m_speed); | ||
|  |         obj.insert("vel_v", frame->m_verticalRate); | ||
|  |         obj.insert("heading", frame->m_heading); | ||
|  |         obj.insert("sats", frame->m_satellitesUsed); | ||
|  |     } | ||
|  | 
 | ||
|  |     if (!subframe->getFrequencyMHz().isEmpty()) { | ||
|  |         obj.insert("frequency", std::round(subframe->getFrequencyMHz().toFloat() * 100.0) / 100.0); | ||
|  |     } | ||
|  | 
 | ||
|  |     if (subframe->getType() != "RS41") { | ||
|  |         obj.insert("subtype", subframe->getType()); | ||
|  |     } | ||
|  | 
 | ||
|  |     //qDebug() << obj;
 | ||
|  |     QJsonArray payloads { | ||
|  |         obj | ||
|  |     }; | ||
|  | 
 | ||
|  |     QJsonDocument doc(payloads); | ||
|  |     QByteArray data = doc.toJson(); | ||
|  | 
 | ||
|  |     QUrl url(QString("https://api.v2.sondehub.org/sondes/telemetry")); | ||
|  | 
 | ||
|  |     QNetworkRequest request(url); | ||
|  |     request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); | ||
|  |     request.setHeader(QNetworkRequest::UserAgentHeader, "sdrangel"); | ||
|  |     request.setRawHeader("Date", QDateTime::currentDateTimeUtc().toString(Qt::ISODateWithMs).toLatin1()); | ||
|  | 
 | ||
|  |     m_networkManager->put(request, data); | ||
|  | } | ||
|  | 
 | ||
|  | void SondeHub::updatePosition( | ||
|  |     const QString& callsign, | ||
|  |     float latitude, | ||
|  |     float longitude, | ||
|  |     float altitude, | ||
|  |     const QString& radio, | ||
|  |     const QString& antenna, | ||
|  |     const QString& email, | ||
|  |     bool mobile | ||
|  |     ) | ||
|  | { | ||
|  |     QJsonArray position { | ||
|  |         latitude, longitude, altitude | ||
|  |     }; | ||
|  | 
 | ||
|  |     QJsonObject obj { | ||
|  |         {"software_name", "SDRangel"}, | ||
|  |         {"software_version", qApp->applicationVersion()}, | ||
|  |         {"uploader_callsign", callsign}, | ||
|  |         {"uploader_position", position}, | ||
|  |         {"uploader_radio", radio}, | ||
|  |         {"uploader_antenna", antenna}, | ||
|  |         {"uploader_contact_email", email}, | ||
|  |         {"mobile", mobile} | ||
|  |     }; | ||
|  | 
 | ||
|  |     QJsonDocument doc(obj); | ||
|  |     QByteArray data = doc.toJson(); | ||
|  | 
 | ||
|  |     QUrl url(QString("https://api.v2.sondehub.org/listeners")); | ||
|  | 
 | ||
|  |     QNetworkRequest request(url); | ||
|  |     request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); | ||
|  |     request.setHeader(QNetworkRequest::UserAgentHeader, "sdrangel"); | ||
|  | 
 | ||
|  |     m_networkManager->put(request, data); | ||
|  | } | ||
|  | 
 | ||
|  | void SondeHub::handleReply(QNetworkReply* reply) | ||
|  | { | ||
|  |     if (reply) | ||
|  |     { | ||
|  |         if (!reply->error()) | ||
|  |         { | ||
|  |             QByteArray bytes = reply->readAll(); | ||
|  |             //qDebug() << bytes;
 | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             qDebug() << "SondeHub::handleReply: error: " << reply->error() << reply->readAll(); | ||
|  |         } | ||
|  |         reply->deleteLater(); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         qDebug() << "SondeHub::handleReply: reply is null"; | ||
|  |     } | ||
|  | } |