diff --git a/plugins/feature/radiosonde/radiosondegui.cpp b/plugins/feature/radiosonde/radiosondegui.cpp
index ecf023eb5..ec381a9c7 100644
--- a/plugins/feature/radiosonde/radiosondegui.cpp
+++ b/plugins/feature/radiosonde/radiosondegui.cpp
@@ -157,6 +157,13 @@ RadiosondeGUI::RadiosondeGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, F
     connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
 
     m_sondeHub = SondeHub::create();
+    if (m_sondeHub)
+    {
+        connect(m_sondeHub, &SondeHub::prediction, this, &RadiosondeGUI::handlePrediction);
+        connect(&m_predicitionTimer, &QTimer::timeout, this, &RadiosondeGUI::requestPredictions);
+        m_predicitionTimer.setInterval(60 * 1000);
+        m_predicitionTimer.setSingleShot(false);
+    }
 
     // Initialise chart
     ui->chart->setRenderHint(QPainter::Antialiasing);
@@ -257,12 +264,14 @@ void RadiosondeGUI::displaySettings()
     ui->y2->setCurrentIndex((int)m_settings.m_y2);
 
     ui->feed->setChecked(m_settings.m_feedEnabled);
+    ui->showPredictedPaths->setChecked(m_settings.m_showPredictedPaths);
 
     getRollupContents()->restoreState(m_rollupState);
     blockApplySettings(false);
     getRollupContents()->arrangeRollups();
 
     updatePosition();
+    applyShowPredictedPaths();
 }
 
 void RadiosondeGUI::onMenuDialogCalled(const QPoint &p)
@@ -673,6 +682,10 @@ void RadiosondeGUI::updateRadiosondes(RS41Frame *message, QDateTime dateTime)
             MainCore::instance()->getSettings().getAltitude()
             );
     }
+
+    if (!found) {
+        requestPredictions();
+    }
 }
 
 void RadiosondeGUI::on_radiosondes_itemSelectionChanged()
@@ -908,16 +921,38 @@ void RadiosondeGUI::on_deleteAll_clicked()
     {
         QString serial = ui->radiosondes->item(row, RADIOSONDE_COL_SERIAL)->text();
         // Remove from map
-        sendToMap(serial, "",
-            "", "",
-            "", 0.0f,
-            0.0f, 0.0f, 0.0f, QDateTime(),
-            0.0f);
+        clearFromMapFeature(serial, 0);
         // Remove from table
         ui->radiosondes->removeRow(row);
         // Remove from hash and free memory
         delete m_radiosondes.take(serial);
     }
+    deletePredictedPaths();
+}
+
+void RadiosondeGUI::deletePredictedPaths()
+{
+    for (const auto& prediction : m_predictions) {
+        clearFromMapFeature(prediction, 3);
+    }
+    m_predictions.clear();
+}
+
+void RadiosondeGUI::clearFromMapFeature(const QString& name, int type)
+{
+    QList<ObjectPipe*> mapPipes;
+    MainCore::instance()->getMessagePipes().getMessagePipes(m_radiosonde, "mapitems", mapPipes);
+
+    for (const auto& pipe : mapPipes)
+    {
+        MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
+        SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem();
+        swgMapItem->setName(new QString(name));
+        swgMapItem->setImage(new QString(""));
+        swgMapItem->setType(type);
+        MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_radiosonde, swgMapItem);
+        messageQueue->push(msg);
+    }
 }
 
 void RadiosondeGUI::makeUIConnections()
@@ -928,6 +963,7 @@ void RadiosondeGUI::makeUIConnections()
     QObject::connect(ui->y2, qOverload<int>(&QComboBox::currentIndexChanged), this, &RadiosondeGUI::on_y2_currentIndexChanged);
     QObject::connect(ui->deleteAll, &QPushButton::clicked, this, &RadiosondeGUI::on_deleteAll_clicked);
     QObject::connect(ui->feed, &ButtonSwitch::clicked, this, &RadiosondeGUI::on_feed_clicked);
+    QObject::connect(ui->showPredictedPaths, &ButtonSwitch::clicked, this, &RadiosondeGUI::on_showPredictedPaths_clicked);
 }
 
 void RadiosondeGUI::on_feed_clicked(bool checked)
@@ -956,6 +992,28 @@ void RadiosondeGUI::feedSelect(const QPoint& p)
     }
 }
 
+void RadiosondeGUI::on_showPredictedPaths_clicked(bool checked)
+{
+    m_settings.m_showPredictedPaths = checked;
+    m_settingsKeys.append("showPredictedPaths");
+    applySettings();
+    applyShowPredictedPaths();
+}
+
+void RadiosondeGUI::applyShowPredictedPaths()
+{
+    if (m_settings.m_showPredictedPaths)
+    {
+        requestPredictions();
+        m_predicitionTimer.start();
+    }
+    else
+    {
+        m_predicitionTimer.stop();
+        deletePredictedPaths();
+    }
+}
+
 // Get names of devices with radiosonde demods, for SondeHub Radio string
 QStringList RadiosondeGUI::getRadios()
 {
@@ -965,7 +1023,7 @@ QStringList RadiosondeGUI::getRadios()
 
     for (const auto& channel : channels)
     {
-        DeviceAPI *device = mainCore->getDevice(channel.m_index);
+        DeviceAPI *device = mainCore->getDevice(channel.m_superIndex);
         if (device)
         {
             QString name = device->getHardwareId();
@@ -1019,6 +1077,71 @@ void RadiosondeGUI::updatePosition()
     }
 }
 
+void RadiosondeGUI::requestPredictions()
+{
+    if (m_sondeHub && m_settings.m_showPredictedPaths)
+    {
+        for (int row = 0; row < ui->radiosondes->rowCount(); row++)
+        {
+            QString serial = ui->radiosondes->item(row, RADIOSONDE_COL_SERIAL)->text();
+            m_sondeHub->getPrediction(serial);
+        }
+    }
+}
+
+void RadiosondeGUI::handlePrediction(const QString& serial, const QList<SondeHub::Position>& positions)
+{
+    if (positions.size() < 2) {
+        return;
+    }
+
+    // Send to Map feature
+    QList<ObjectPipe*> mapPipes;
+    MainCore::instance()->getMessagePipes().getMessagePipes(m_radiosonde, "mapitems", mapPipes);
+
+    if (mapPipes.size() > 0)
+    {
+        QString name = QString("%1_prediction").arg(serial);
+
+        for (const auto& pipe : mapPipes)
+        {
+            MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
+            SWGSDRangel::SWGMapItem *swgMapItem = new SWGSDRangel::SWGMapItem();
+
+            swgMapItem->setName(new QString(name));
+            swgMapItem->setLatitude(positions[0].m_latitude);
+            swgMapItem->setLongitude(positions[0].m_longitude);
+            swgMapItem->setAltitude(positions[0].m_altitude);
+            QString image = QString("none");
+            swgMapItem->setImage(new QString(image));
+            swgMapItem->setImageRotation(0);
+            swgMapItem->setFixedPosition(true);
+            swgMapItem->setLabel(new QString(serial));
+            swgMapItem->setAltitudeReference(0);
+            QList<SWGSDRangel::SWGMapCoordinate *> *coords = new QList<SWGSDRangel::SWGMapCoordinate *>();
+
+            for (const auto& position : positions)
+            {
+                SWGSDRangel::SWGMapCoordinate* c = new SWGSDRangel::SWGMapCoordinate();
+                c->setLatitude(position.m_latitude);
+                c->setLongitude(position.m_longitude);
+                c->setAltitude(position.m_altitude);
+                coords->append(c);
+            }
+
+            swgMapItem->setCoordinates(coords);
+            swgMapItem->setType(3);
+
+            MainCore::MsgMapItem *msg = MainCore::MsgMapItem::create(m_radiosonde, swgMapItem);
+            messageQueue->push(msg);
+
+            if (!m_predictions.contains(name)) {
+                m_predictions.append(name);
+            }
+        }
+    }
+}
+
 void RadiosondeGUI::preferenceChanged(int elementType)
 {
     Preferences::ElementType pref = (Preferences::ElementType)elementType;
diff --git a/plugins/feature/radiosonde/radiosondegui.h b/plugins/feature/radiosonde/radiosondegui.h
index 9afb619cd..fd6c31d47 100644
--- a/plugins/feature/radiosonde/radiosondegui.h
+++ b/plugins/feature/radiosonde/radiosondegui.h
@@ -108,6 +108,9 @@ private:
     static const int m_minMobilePositionUpdateTime = 30; // In seconds
     static const int m_minFixedPositionUpdateTime = 5 * 60;
 
+    QTimer m_predicitionTimer;
+    QStringList m_predictions;
+
     explicit RadiosondeGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr);
     virtual ~RadiosondeGUI();
 
@@ -130,6 +133,9 @@ private:
     float getData(RadiosondeSettings::ChartData dataType, RadiosondeData *radiosonde, RS41Frame *message);
     void updatePosition();
     QStringList getRadios();
+    void applyShowPredictedPaths();
+    void deletePredictedPaths();
+    void clearFromMapFeature(const QString& name, int type);
 
     enum RadiosondeCol {
         RADIOSONDE_COL_SERIAL,
@@ -168,6 +174,9 @@ private slots:
     void on_deleteAll_clicked();
     void on_feed_clicked(bool checked);
     void feedSelect(const QPoint& p);
+    void on_showPredictedPaths_clicked(bool checked);
+    void requestPredictions();
+    void handlePrediction(const QString& serial, const QList<SondeHub::Position>& positions);
     void preferenceChanged(int elementType);
 
 };
diff --git a/plugins/feature/radiosonde/radiosondegui.ui b/plugins/feature/radiosonde/radiosondegui.ui
index eee177b19..106c74341 100644
--- a/plugins/feature/radiosonde/radiosondegui.ui
+++ b/plugins/feature/radiosonde/radiosondegui.ui
@@ -31,7 +31,7 @@
    <string>Radiosonde</string>
   </property>
   <property name="layoutDirection">
-   <enum>Qt::LeftToRight</enum>
+   <enum>Qt::LayoutDirection::LeftToRight</enum>
   </property>
   <widget class="QWidget" name="tableContainer" native="true">
    <property name="geometry">
@@ -76,20 +76,20 @@
        </sizepolicy>
       </property>
       <property name="orientation">
-       <enum>Qt::Vertical</enum>
+       <enum>Qt::Orientation::Vertical</enum>
       </property>
       <widget class="QTableWidget" name="radiosondes">
        <property name="toolTip">
         <string>Radiosondes</string>
        </property>
        <property name="editTriggers">
-        <set>QAbstractItemView::NoEditTriggers</set>
+        <set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
        </property>
        <property name="selectionMode">
-        <enum>QAbstractItemView::SingleSelection</enum>
+        <enum>QAbstractItemView::SelectionMode::SingleSelection</enum>
        </property>
        <property name="selectionBehavior">
-        <enum>QAbstractItemView::SelectRows</enum>
+        <enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>
        </property>
        <column>
         <property name="text">
@@ -416,6 +416,23 @@
             </property>
            </widget>
           </item>
+          <item>
+           <widget class="ButtonSwitch" name="showPredictedPaths">
+            <property name="toolTip">
+             <string>Show predicted paths on map</string>
+            </property>
+            <property name="text">
+             <string>...</string>
+            </property>
+            <property name="icon">
+             <iconset resource="../../../sdrgui/resources/res.qrc">
+              <normaloff>:/logarithmic.png</normaloff>:/logarithmic.png</iconset>
+            </property>
+            <property name="checkable">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
          </layout>
         </item>
         <item>
diff --git a/plugins/feature/radiosonde/radiosondesettings.cpp b/plugins/feature/radiosonde/radiosondesettings.cpp
index c45c27b90..35140dcd2 100644
--- a/plugins/feature/radiosonde/radiosondesettings.cpp
+++ b/plugins/feature/radiosonde/radiosondesettings.cpp
@@ -60,6 +60,7 @@ void RadiosondeSettings::resetToDefaults()
     m_displayPosition = false;
     m_mobile = false;
     m_email = "";
+    m_showPredictedPaths = false;
 
     for (int i = 0; i < RADIOSONDES_COLUMNS; i++)
     {
@@ -95,6 +96,7 @@ QByteArray RadiosondeSettings::serialize() const
     s.writeBool(17, m_displayPosition);
     s.writeBool(18, m_mobile);
     s.writeString(19, m_email);
+    s.writeBool(20, m_showPredictedPaths);
 
 
     for (int i = 0; i < RADIOSONDES_COLUMNS; i++) {
@@ -159,6 +161,7 @@ bool RadiosondeSettings::deserialize(const QByteArray& data)
         d.readBool(17, &m_displayPosition, false);
         d.readBool(18, &m_mobile, false);
         d.readString(19, &m_email, "");
+        d.readBool(20, &m_showPredictedPaths, false);
 
         for (int i = 0; i < RADIOSONDES_COLUMNS; i++) {
             d.readS32(300 + i, &m_radiosondesColumnIndexes[i], i);
@@ -224,6 +227,9 @@ void RadiosondeSettings::applySettings(const QStringList& settingsKeys, const Ra
     if (settingsKeys.contains("email")) {
         m_email = settings.m_email;
     }
+    if (settingsKeys.contains("showPredictedPaths")) {
+        m_showPredictedPaths = settings.m_showPredictedPaths;
+    }
     if (settingsKeys.contains("workspaceIndex")) {
         m_workspaceIndex = settings.m_workspaceIndex;
     }
@@ -292,6 +298,9 @@ QString RadiosondeSettings::getDebugString(const QStringList& settingsKeys, bool
     if (settingsKeys.contains("email") || force) {
         ostr << " m_email: " << m_email.toStdString();
     }
+    if (settingsKeys.contains("showPredictedPaths") || force) {
+        ostr << " m_showPredictedPaths: " << m_showPredictedPaths;
+    }
     if (settingsKeys.contains("workspaceIndex") || force) {
         ostr << " m_workspaceIndex: " << m_workspaceIndex;
     }
diff --git a/plugins/feature/radiosonde/radiosondesettings.h b/plugins/feature/radiosonde/radiosondesettings.h
index 1f7071027..2112f26fa 100644
--- a/plugins/feature/radiosonde/radiosondesettings.h
+++ b/plugins/feature/radiosonde/radiosondesettings.h
@@ -62,6 +62,7 @@ struct RadiosondeSettings
     bool m_displayPosition;
     bool m_mobile;
     QString m_email;
+    bool m_showPredictedPaths;
 
     int m_radiosondesColumnIndexes[RADIOSONDES_COLUMNS];
     int m_radiosondesColumnSizes[RADIOSONDES_COLUMNS];
diff --git a/plugins/feature/radiosonde/readme.md b/plugins/feature/radiosonde/readme.md
index 6fd8e850a..55cad6f4d 100644
--- a/plugins/feature/radiosonde/readme.md
+++ b/plugins/feature/radiosonde/readme.md
@@ -7,7 +7,7 @@ based on data received via [Radiosonde Demodulators](../../channelrx/demodradios
 
 The chart can plot two data series vs time for the radiosonde selected in the table.
 
-The Radiosonde feature can draw balloons objects on the [Map](../../feature/map/readme.md) feature in 2D and 3D.
+The Radiosonde feature can draw balloons objects and predicted paths on the [Map](../../feature/map/readme.md) feature in 2D and 3D.
 
 Received data can be forwarded to [SondeHub](https://sondehub.org/). Your location can be displayed on the SondeHub map, as either a stationary receiver or chase car.
 
@@ -48,6 +48,7 @@ The Radiosonde feature can plot balloons (during ascent) and parachutes (during
 To use, simply open a Map feature and the Radiosonde plugin will display objects based upon the data it receives from that point.
 Selecting a radiosonde item on the map will display a text bubble containing information from the above table.
 To centre the map on an item in the table, double click in the Lat or Lon columns.
+Predicted paths can be displayed by checking the Show Predicted Paths button. The path is predicted by SondeHub.
 
 ![Radiosonde on map](../../../doc/img/Radiosonde_plugin_map.png)
 
diff --git a/sdrbase/util/sondehub.cpp b/sdrbase/util/sondehub.cpp
index 9cb76158c..d15e665f7 100644
--- a/sdrbase/util/sondehub.cpp
+++ b/sdrbase/util/sondehub.cpp
@@ -183,6 +183,17 @@ void SondeHub::updatePosition(
     m_networkManager->put(request, data);
 }
 
+void SondeHub::getPrediction(const QString& serial)
+{
+    QUrl url(QString("https://api.v2.sondehub.org/predictions?vehicles=%1").arg(serial));
+
+    QNetworkRequest request(url);
+    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+    request.setHeader(QNetworkRequest::UserAgentHeader, "sdrangel");
+
+    m_networkManager->get(request);
+}
+
 void SondeHub::handleReply(QNetworkReply* reply)
 {
     if (reply)
@@ -221,7 +232,53 @@ void SondeHub::handleReply(QNetworkReply* reply)
                         }
                     }
                 }
-                //qDebug() << "SondeHub::handleReply: obj" << QJsonDocument(obj);
+                 //qDebug() << "SondeHub::handleReply: obj" << QJsonDocument(obj);
+            }
+            else if (document.isArray())
+            {
+                QJsonArray array = document.array();
+
+                for (auto arrayRef : array)
+                {
+                    if (arrayRef.isObject())
+                    {
+                        QJsonObject obj = arrayRef.toObject();
+
+                        if (obj.contains(QStringLiteral("vehicle")) && obj.contains(QStringLiteral("data")))
+                        {
+                            QJsonArray data;
+                            // Perhaps a bug that data is a string rather than an array?
+                            if (obj.value(QStringLiteral("data")).isString())
+                            {
+                                QJsonDocument dataDocument = QJsonDocument::fromJson(obj.value(QStringLiteral("data")).toString().toUtf8());
+                                data = dataDocument.array();
+                            }
+                            else
+                            {
+                                data = obj.value(QStringLiteral("data")).toArray();
+                            }
+
+                            QList<Position> positions;
+                            for (auto dataObjRef : data)
+                            {
+                                QJsonObject positionObj = dataObjRef.toObject();
+                                Position position;
+
+                                position.m_dateTime = QDateTime::fromSecsSinceEpoch(positionObj.value(QStringLiteral("time")).toInt());
+                                position.m_latitude = positionObj.value(QStringLiteral("lat")).toDouble();
+                                position.m_longitude = positionObj.value(QStringLiteral("lon")).toDouble();
+                                position.m_altitude = positionObj.value(QStringLiteral("alt")).toDouble();
+                                positions.append(position);
+                            }
+
+                            emit prediction(obj.value("vehicle").toString(), positions);
+                        }
+                    }
+                    else
+                    {
+                        qDebug() << "SondeHub::handleReply:" << bytes;
+                    }
+                }
             }
             else
             {
diff --git a/sdrbase/util/sondehub.h b/sdrbase/util/sondehub.h
index 6ad663a6f..8409ac94b 100644
--- a/sdrbase/util/sondehub.h
+++ b/sdrbase/util/sondehub.h
@@ -36,6 +36,13 @@ protected:
 
 public:
 
+    struct Position {
+        float m_latitude;
+        float m_longitude;
+        float m_altitude;
+        QDateTime m_dateTime;
+    };
+
     static SondeHub* create();
 
     ~SondeHub();
@@ -61,10 +68,14 @@ public:
         bool mobile
     );
 
+    void getPrediction(const QString& serial);
 
 private slots:
     void handleReply(QNetworkReply* reply);
 
+signals:
+    void prediction(const QString& serial, const QList<Position>& path);
+
 private:
 
     QNetworkAccessManager *m_networkManager;