Esta pregunta me la hice ya algunos meses atrás y encontré la solución quiero compartirla con ustedes.
Si se pueden enviar mensajes SMS con una aplicación propia, se necesita lo siguiente:
- Una computadora o servidor física (no rentado, ni un servicio)
- Un módem
GSM
o Banca Ancha Móvil
(instalado con drivers
)
- Un chip de alguna compañía de celular (de preferencia con
SMS
ilimitados)
- Una aplicación que pueda enviar
GSM AT Command
De esta manera podemos hacer nuestro servidor de envió de SMS
y pensando en enviar muchos mensajes, evidentemente nos conviene mas pagar una renta por SMS
ilimitados que pagar una cantidad fija por cada mensaje.
Existen los Modems GSM, Banda Ancha Movil (BAM), como los que muestro acontinuación:
BAM
GSM
Yo hice la prueba con esta BAM:
Huawei E153 Módem USB GSM/GPRS/EDGE 850/900/1800/1900 MHz
La conecte a la computadora con el chip (tarjeta SIM) de mi compañía de celular, instale los drivers correspondientes y probé con la app propia de la compañía Telcel en este caso.
Después encontré un software hecho en c#, les explico y les comparto la liga:
Descargar código de: SMS aplicación c#
La aplicación se conecta por un puerto COM al modem
private void btnOK_Click(object sender, EventArgs e)
{
try
{
//Open communication port
this.port = objclsSMS.OpenPort(this.cboPortName.Text, Convert.ToInt32(this.cboBaudRate.Text),
Convert.ToInt32(this.cboDataBits.Text), Convert.ToInt32(this.txtReadTimeOut.Text), Convert.ToInt32(this.txtWriteTimeOut.Text));
if (this.port != null)
{
this.gboPortSettings.Enabled = false;
//MessageBox.Show("Modem is connected at PORT " + this.cboPortName.Text);
this.statusBar1.Text = "Modem is connected at PORT " + this.cboPortName.Text;
//Add tab pages
this.tabSMSapplication.TabPages.Add(tbSendSMS);
this.tabSMSapplication.TabPages.Add(tbReadSMS);
this.tabSMSapplication.TabPages.Add(tbDeleteSMS);
this.lblConnectionStatus.Text = "Connected at " + this.cboPortName.Text;
this.btnDisconnect.Enabled = true;
}
else
{
//MessageBox.Show("Invalid port settings");
this.statusBar1.Text = "Invalid port settings";
}
}
catch (Exception ex)
{
ErrorLog(ex.Message);
}
}
Se intenta conectar:
//Open Port
public SerialPort OpenPort(string p_strPortName, int p_uBaudRate, int p_uDataBits, int p_uReadTimeout, int p_uWriteTimeout)
{
receiveNow = new AutoResetEvent(false);
SerialPort port = new SerialPort();
try
{
port.PortName = p_strPortName; //COM1
port.BaudRate = p_uBaudRate; //9600
port.DataBits = p_uDataBits; //8
port.StopBits = StopBits.One; //1
port.Parity = Parity.None; //None
port.ReadTimeout = p_uReadTimeout; //300
port.WriteTimeout = p_uWriteTimeout; //300
port.Encoding = Encoding.GetEncoding("iso-8859-1");
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
port.Open();
port.DtrEnable = true;
port.RtsEnable = true;
}
catch (Exception ex)
{
throw ex;
}
return port;
}
Una vez conectado se pueden usar las funciones de las siguientes pestañas:
Enviar SMS
Muestro el código utilizado para enviar los SMS
btnSendSMS_Click
private void btnSendSMS_Click(object sender, EventArgs e)
{
//.............................................. Send SMS ....................................................
try
{
if (objclsSMS.sendMsg(this.port, this.txtSIM.Text, this.txtMessage.Text))
{
//MessageBox.Show("Message has sent successfully");
this.statusBar1.Text = "Message has sent successfully";
}
else
{
//MessageBox.Show("Failed to send message");
this.statusBar1.Text = "Failed to send message";
}
}
catch (Exception ex)
{
ErrorLog(ex.Message);
}
}
sendMsg
public bool sendMsg(SerialPort port, string PhoneNo, string Message)
{
bool isSend = false;
try
{
string recievedData = ExecCommand(port,"AT", 300, "No phone connected");
recievedData = ExecCommand(port,"AT+CMGF=1", 300, "Failed to set message format.");
String command = "AT+CMGS=\"" + PhoneNo + "\"";
recievedData = ExecCommand(port,command, 300, "Failed to accept phoneNo");
command = Message + char.ConvertFromUtf32(26) + "\r";
recievedData = ExecCommand(port,command, 3000, "Failed to send message"); //3 seconds
if (recievedData.EndsWith("\r\nOK\r\n"))
{
isSend = true;
}
else if (recievedData.Contains("ERROR"))
{
isSend = false;
}
return isSend;
}
catch (Exception ex)
{
throw ex;
}
}
Como se muestra en esta línea:
String command = "AT+CMGS=\"" + PhoneNo + "\"";
el módem recibe AT COMMANDS
o también conocidos como Conjunto de comandos Hayes
Leer SMS
btnReadSMS_Click
private void btnReadSMS_Click(object sender, EventArgs e)
{
try
{
//count SMS
int uCountSMS = objclsSMS.CountSMSmessages(this.port);
if (uCountSMS > 0)
{
#region Command
string strCommand = "AT+CMGL=\"ALL\"";
if (this.rbReadAll.Checked)
{
strCommand = "AT+CMGL=\"ALL\"";
}
else if (this.rbReadUnRead.Checked)
{
strCommand = "AT+CMGL=\"REC UNREAD\"";
}
else if (this.rbReadStoreSent.Checked)
{
strCommand = "AT+CMGL=\"STO SENT\"";
}
else if (this.rbReadStoreUnSent.Checked)
{
strCommand = "AT+CMGL=\"STO UNSENT\"";
}
#endregion
// If SMS exist then read SMS
#region Read SMS
//.............................................. Read all SMS ....................................................
objShortMessageCollection = objclsSMS.ReadSMS(this.port, strCommand);
foreach (ShortMessage msg in objShortMessageCollection)
{
ListViewItem item = new ListViewItem(new string[] { msg.Index, msg.Sent, msg.Sender, msg.Message });
item.Tag = msg;
lvwMessages.Items.Add(item);
}
#endregion
}
else
{
lvwMessages.Clear();
//MessageBox.Show("There is no message in SIM");
this.statusBar1.Text = "There is no message in SIM";
}
}
catch (Exception ex)
{
ErrorLog(ex.Message);
}
}
ReadSMS
public ShortMessageCollection ReadSMS(SerialPort port, string p_strCommand)
{
// Set up the phone and read the messages
ShortMessageCollection messages = null;
try
{
#region Execute Command
// Check connection
ExecCommand(port,"AT", 300, "No phone connected");
// Use message format "Text mode"
ExecCommand(port,"AT+CMGF=1", 300, "Failed to set message format.");
// Use character set "PCCP437"
ExecCommand(port,"AT+CSCS=\"PCCP437\"", 300, "Failed to set character set.");
// Select SIM storage
ExecCommand(port,"AT+CPMS=\"SM\"", 300, "Failed to select message storage.");
// Read the messages
string input = ExecCommand(port, p_strCommand, 5000, "Failed to read the messages.");
#endregion
#region Parse messages
messages = ParseMessages(input);
#endregion
}
catch (Exception ex)
{
throw ex;
}
if (messages != null)
return messages;
else
return null;
}
Eliminar SMS
btnDeleteSMS_Click
private void btnDeleteSMS_Click(object sender, EventArgs e)
{
try
{
//Count SMS
int uCountSMS = objclsSMS.CountSMSmessages(this.port);
if (uCountSMS > 0)
{
DialogResult dr = MessageBox.Show("Are u sure u want to delete the SMS?", "Delete confirmation", MessageBoxButtons.YesNo);
if (dr.ToString() == "Yes")
{
#region Delete SMS
if (this.rbDeleteAllSMS.Checked)
{
//...............................................Delete all SMS ....................................................
#region Delete all SMS
string strCommand = "AT+CMGD=1,4";
if (objclsSMS.DeleteMsg(this.port, strCommand))
{
//MessageBox.Show("Messages has deleted successfuly ");
this.statusBar1.Text = "Messages has deleted successfuly";
}
else
{
//MessageBox.Show("Failed to delete messages ");
this.statusBar1.Text = "Failed to delete messages";
}
#endregion
}
else if (this.rbDeleteReadSMS.Checked)
{
//...............................................Delete Read SMS ....................................................
#region Delete Read SMS
string strCommand = "AT+CMGD=1,3";
if (objclsSMS.DeleteMsg(this.port, strCommand))
{
//MessageBox.Show("Messages has deleted successfuly");
this.statusBar1.Text = "Messages has deleted successfuly";
}
else
{
//MessageBox.Show("Failed to delete messages ");
this.statusBar1.Text = "Failed to delete messages";
}
#endregion
}
#endregion
}
}
}
catch (Exception ex)
{
ErrorLog(ex.Message);
}
}
DeleteMsg
#region Delete SMS
public bool DeleteMsg(SerialPort port , string p_strCommand)
{
bool isDeleted = false;
try
{
#region Execute Command
string recievedData = ExecCommand(port,"AT", 300, "No phone connected");
recievedData = ExecCommand(port,"AT+CMGF=1", 300, "Failed to set message format.");
String command = p_strCommand;
recievedData = ExecCommand(port,command, 300, "Failed to delete message");
#endregion
if (recievedData.EndsWith("\r\nOK\r\n"))
{
isDeleted = true;
}
if (recievedData.Contains("ERROR"))
{
isDeleted = false;
}
return isDeleted;
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
Anexo un poco de información sobre los AT COMMANDS
Conjunto de comandos Hayes
El conjunto de comandos Hayes es un lenguaje desarrollado por la compañía
Hayes Communications que prácticamente se convirtió en estándar
abierto de comandos para configurar y parametrizar módems. Los
caracteres «AT», que preceden a todos los comandos, significan
«Atención», e hicieron que se conociera también a este conjunto de
comandos como comandos AT. Midiendo la longitud de los bits se puede
determinar en detalle la velocidad de transmisión.
Comandos
AT
Sirve para verificar si el módulo SIM900 está funcionando adecuadamente para
entrar en modo comando.
Al enviar AT el SIM deberá contestarnos con un OK.
AT+CGMI
Veremos en nombre del fabricante
ATI
Ver la información del producto.
AT+IPR=?
Preguntar el Baud Rate en el que puede operar el SIM
AT+IPR?
Sirve para preguntar el Baud Rate actual
AT+IPR=XXXX
Configuremos a la frecuencia deseada
AT+COPS?
Nombre de la compañía telefónica
AT+CGSN
Visualizar el IMEI del chip utilizado
AT+CSCS?
Tipo de texto
AT+CSCS=”XXX”
Configurar a tipo de texto
AT+CMGF?
Ver el formato de un mensaje, ya sea PDU(0) o SMS(1)”
AT+CMGS=04455XXXXXXXX
Enviar un SMS Se despliega el símbolo mayor que > Escribir mensaje y al finalizar
presiona Ctrl+Z retornará OK si el SMS se envió correctamente.
AT+CMGL=ALL
Sirve para ver todos los mensajes que nos han llegado al SIM
ATD04455XXXXXXXX;
Sirve para hacer una llamada a cualquier teléfono móvil
ATA
Sirve para contestar una llamada
ATH
Sirve para colgar una llamada