Q: Is it possible to make a sip call over gprs with a SIM800 module? I have an Asterisk server on cloud and I want ESP32 devices to register as SIP clients and make a VoIP call over GPRS via SIM800 module. AT commands of SIM800 module allows me to make a GPRS connection and I can send http request and send MQTT messages. However, I couldn't find a way to connect to VoIP server, if possible.
My current code establises MQTT connection over GPRS and make calls over GSM but cannot connect to Asterisk:
// ESP32 Configuration
#define TINY_GSM_MODEM_SIM800
#define SerialMon Serial 
#define SerialAT Serial2 
#define TINY_GSM_DEBUG SerialMon
#define GSM_AUTOBAUD_MIN 9600  /
#define GSM_AUTOBAUD_MAX 38400 
#define TINY_GSM_USE_GPRS true


#define PhoneNumber "xxxxxxxxxxxxxxx" 


#define rcSwitchInterruptPin 35
#define ENABLE_SIM800C 22   
#define BUTTON_PIN 33
#define SOS_BUTTON_ID0 4236140
#define SOS_BUTTON_ID1 4236132
#define SOS_BUTTON_PIN 27

// GPRS internet settings, specific to your SIM card 
const char apn[] = "internet";
const char gprsUser[] = "";
const char gprsPass[] = "";

// MQTT settings
const char *broker = "broker.emqx.io";
const int mqttPort = 1883;
const char * clientID = "esp32-client";
const char * mqttUser = "acido";
const char * mqttPassword = "12345678";


#include <TinyGsmClient.h>
#include <PubSubClient.h>
#include <SPI.h>
#include <Wire.h>
#include <PubSubClient.h>
#include <elapsedMillis.h>
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();

TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
PubSubClient mqtt(client);

uint32_t lastReconnectAttempt = 0;
void mqttCallback(char *, byte *, unsigned int);
boolean mqttConnect();
void DRE_switch();
elapsedSeconds serialLogSeconds;
unsigned int serialLog_Interval = 3;
elapsedSeconds sinyalBekletme;
unsigned int sinyalBekletme_Interval = 3;
elapsedSeconds sosDelay;
unsigned int sosDelay_Interval = 3;
elapsedSeconds kapiacikDelay;
unsigned int kapiacikDelay_Interval = 3;
elapsedSeconds kapiKapaliDelay;
unsigned int kapiKapaliDelay_Interval = 3;
elapsedSeconds gazDelay;
unsigned int gazDelay_Interval = 3;
elapsedSeconds pirDelay;
unsigned int pirDelay_Interval = 3;
elapsedSeconds dumanDelay;
unsigned int dumanDelay_Interval = 3;

void setup()
{
    mqtt.setKeepAlive(60);

    // Set console baud rate
    SerialMon.begin(9600);
    while (!SerialMon)

    delay(10);

    // !!!!!!!!!!!
    mySwitch.enableReceive(35);
    pinMode(BUTTON_PIN, INPUT_PULLDOWN); 
    pinMode(ENABLE_SIM800C, OUTPUT);

    digitalWrite(ENABLE_SIM800C, HIGH);
    delay(3000);
    digitalWrite(ENABLE_SIM800C, LOW);
    // !!!!!!!!!!!

    TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);

    delay(6000);

    // Restart takes quite some time
    // To skip it, call init() instead of restart()

    // if (!modem.restart()) {
    if (!modem.init()) {
        DBG("Failed to restart modem, delaying 10s and retrying");
        // restart autobaud in case GSM just rebooted
        TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
        return;
    }

    String modemInfo = modem.getModemInfo();
    SerialMon.print("setup: Modem Info: ");
    SerialMon.println(modemInfo);

    SerialMon.print("setup: Waiting for network...");
    if (!modem.waitForNetwork())
    {
        SerialMon.println("setup:  fail, wait 5 seconds");
        delay(5000);
        return;
    }
    SerialMon.println("setup:  success");

    if (modem.isNetworkConnected())
        SerialMon.println("setup: Network connected");

#if TINY_GSM_USE_GPRS
    // GPRS connection parameters are usually set after network registration
    SerialMon.print(F("setup: Connecting to apn: "));
    SerialMon.print(apn);
    if (!modem.gprsConnect(apn, gprsUser, gprsPass))
    {
        SerialMon.println("setup:  GPRS Connecting fail, wait 5 seconds");
        delay(5000);
        return;
    }
    SerialMon.println("setup:  GPRS success");

    if (modem.isGprsConnected())
    {
        SerialMon.println("setup: GPRS connected");
    }
#endif

    // MQTT Broker setup
    mqtt.setServer(broker, mqttPort);
    mqtt.setCallback(mqttCallback); 
}

void loop()
{
    bool result;

    // check if we're connected to network
    if (!modem.isNetworkConnected())
    {
        SerialMon.println("loop: modem disconnected");
        if (!modem.waitForNetwork(180000L, true))
        {
            SerialMon.println("loop: modem fail, wait 10 sec");
            delay(10000);
            return;
        }

        if (modem.isNetworkConnected())
        {
            SerialMon.println("loop: Modem re-connected");
        }

        // And make sure GPRS/EPS is still connected
        if (!modem.isGprsConnected())
        {
            SerialMon.println("loop: GPRS disconnected!");
            SerialMon.print(F("loop: Connecting to apn:"));
            SerialMon.print(apn);
            if (!modem.gprsConnect(apn, gprsUser, gprsPass))
            {
                SerialMon.println("loop:  GPRS fail, wait 10 sec");
                delay(10000);
                return;
            }
            if (modem.isGprsConnected())
            {
                SerialMon.println("loop: GPRS reconnected");
            }
        }
    }

    // check if we're connected to MQTT
    if (!mqtt.connected())
    {
        SerialMon.println("loop: === mqtt not connected ===");
        // Reconnect every 10 seconds
        uint32_t t = millis();
        if (t - lastReconnectAttempt > 10000L)
        {
            lastReconnectAttempt = t;
            if (mqttConnect())
            {
                lastReconnectAttempt = 0;
            }
        }
        return;
    }

    if (digitalRead(BUTTON_PIN) == HIGH)
    {
        Serial.println("BUTONA BASILDI");
        result = modem.callNumber(PhoneNumber);
        DBG("Call:", result ? "OK" : "fail");
    }

    // Check RF signals and publish to MQTT

    if (mySwitch.available())
    {
        int num = mySwitch.getReceivedValue();
        Serial.print("Num: ");
        Serial.print(num);
        Serial.print("  Protocol: ");
        Serial.println(mySwitch.getReceivedProtocol());

        if (sosDelay >= sosDelay_Interval)
        {
            if (num == 4236132) // SOS
            {
                Serial.println("SOS Butonuna Basıldı.");
                DRE_switch();
                mqtt.publish("CMR/ESP32s/SENSOR/SOS", "SOS"); // Publish message.
                result = modem.callNumber(PhoneNumber);
                DBG("Call:", result ? "OK" : "fail");
            }
            else
            {
                mqtt.publish("CMR/ESP32s/SENSOR/SOS", "0"); // Publish message.
            }
            sosDelay = 0;
        }

        if (pirDelay >= pirDelay_Interval)
        {
            if (num == 8330345)
            {
                DRE_switch();
                Serial.println("HAREKET ALGILANDI.");
                mqtt.publish("CMR/ESP32s/SENSOR/PIR", "HAREKET ALGILANDI"); // Publish message.
            }
            else
            {
                mqtt.publish("CMR/ESP32s/SENSOR/PIR", "0"); // Publish message
            }
            pirDelay = 0;
        }

        if (kapiacikDelay >= kapiacikDelay_Interval)
        {

            if (num == 5729285) // Kapi acilinca gelen sinyal
            {
                DRE_switch();
                Serial.println("KAPI AÇILDI.");
                mqtt.publish("CMR/ESP32s/SENSOR/KAPIACIK", "1"); // Publish message.
            }
            else
            {
                mqtt.publish("CMR/ESP32s/SENSOR/KAPIACIK", "0"); // Publish message
            }
            kapiacikDelay = 0;
        }

        if (kapiKapaliDelay >= kapiKapaliDelay_Interval)
        {

            if (num == 5729294) // Kapi kapaninca gelen sinyal
            {
                DRE_switch();
                Serial.println("KAPI KAPANDI.");
                mqtt.publish("CMR/ESP32s/SENSOR/KAPIKAPALI", "1"); // Publish message.
            }
            else
            {
                mqtt.publish("CMR/ESP32s/SENSOR/KAPIKAPALI", "0"); // Publish message
            }
            kapiKapaliDelay = 0;
        }

        if (gazDelay >= gazDelay_Interval)
        {
            if (num == 12607491)
            {
                DRE_switch();
                Serial.println("Gas Algılandı.");
                mqtt.publish("CMR/ESP32s/SENSOR/GAS", "GAS ALGILANDI"); // Publish message.
            }
            else
            {
                mqtt.publish("CMR/ESP32s/SENSOR/GAS", "0"); // Publish message
            }
            gazDelay = 0;
        }

        if (dumanDelay >= dumanDelay_Interval)
        {
            if (num == 79974)
            {
                DRE_switch();
                Serial.println("Duman Algılandı .");
                mqtt.publish("CMR/ESP32s/SENSOR/DUMAN", "DUMAN ALGILANDI"); // Publish message.
            }
            else
            {
                mqtt.publish("CMR/ESP32s/SENSOR/DUMAN", "0"); // Publish message
            }
            dumanDelay = 0;
        }
    } // end if mySwitch.available

    modem.maintain();
    mqtt.loop(); // Handling MQTT on the background.
} // end of loop


boolean mqttConnect()
{
    // Connect to MQTT Broker
    SerialMon.print("mqttConnect:  MQTT trying to connect: ");
    SerialMon.print(broker);

    // Connect to MQTT Broker with password protected
    boolean status = mqtt.connect(clientID, mqttUser, mqttPassword);

    // boolean status = mqtt.connect(clientID); // without password

    if (status == false)
    {
        SerialMon.println("mqttConnect:  MQTT Connection Fail");
        return false;
    }
    SerialMon.println("mqttConnect:  *** MQTT CONNECTED *** ");

    mqtt.publish("topic/akes", "Client connection started");
    mqtt.subscribe("topic/akes"); // subscribe to topic
    
    return mqtt.connected();
}


void mqttCallback(char *topic, byte *payload, unsigned int len)
{
    // Handle message arrived
    SerialMon.print("mqttCallback:  Message arrived [");
    SerialMon.print(topic);
    SerialMon.print("]: ");
    SerialMon.write(payload, len);
    SerialMon.println();
}


void DRE_switch()
{
    // Disable Reset Enable function for RF module
    mySwitch.disableReceive();
    mySwitch.resetAvailable();
    mySwitch.enableReceive(rcSwitchInterruptPin);
}

