B4R Tutorial GSM / GPRS - Control the Arduino with SMS messages

Discussion in 'B4R Tutorials' started by Erel, May 11, 2016.

  1. Erel

    Erel Administrator Staff Member Licensed User

    [​IMG]

    The GSM shield allows the Arduino to connect to cellular networks. This opens the door for many interesting outdoor solutions.

    There are all kinds of shields available. Make sure that the shield you are using is configured to work with pins other than 0 and 1 (which are used for programming the Arduino). We will use SoftwareSerial with AsyncStreams to communicate with the GSM module.

    The GSM shield is controlled with AT commands. There are many online resources about the supported commands. Here is a one: http://www.codeproject.com/Articles/85636/Introduction-to-AT-commands-and-its-uses

    The GSM code module, included in the attached example, implements the most common commands.

    - Sending and receiving SMS messages.
    - Making phone calls (the speaker part is not implemented).
    - Incoming phone calls.
    - Checking the registration status.

    Only one task can be done at a time. So there is a "busy" flag that is set and cleared to make sure that commands do not mix.

    In this specific example the led is controlled with SMS messages. The button sends a "click!!!" message:
    Code:
    Sub btn_StateChanged (State As Boolean)
       
    If State = False Then
         GSM.SendSMS(phoneNumber, 
    "Click!!!")
       
    End If
    End Sub

    Sub MessageArrived(msg() As Byte)
       
    If msg = "On" Then
         
    led.DigitalWrite(True)
       
    Else if msg = "Off" Then
         
    led.DigitalWrite(False)
       
    Else
         
    Log("error: ", msg)
       
    End If
    End Sub
    Useful information about these shields:
    http://www.seeedstudio.com/wiki/GPRS_Shield_V1.0
    http://www.seeedstudio.com/wiki/GPRS_Shield_V2.0
     

    Attached Files:

    Last edited: Oct 8, 2017
  2. Beja

    Beja Expert Licensed User

    Hi Erel,
    I am just wondering if this code can be ported to GPS/GPRS modem + B4J, and what modifications are necessary if that's possible.
     
  3. Erel

    Erel Administrator Staff Member Licensed User

    Yes, it can be ported. You need to use jSerial to interact with the modem. Go over the code it shouldn't be too difficult to port it.
     
    Beja likes this.
  4. JOANORSKY

    JOANORSKY Member Licensed User

    This might be a slightly off topic but... i have always wondered how do some companies change their caller ID when sending SMS. I know that this can be done using an Asterisk PBX.. but wouldn't this great if done inside a microcontroller such as the Arduino's ATMEGA ?

    This can be called as a spoof and can have a lot of uses.. such as publicity to the customers of a certain shop, and for that purpose it is legal as far as i know (it is legal over here in Portugal as well as in all EU countries and US generally speaking).

    I know for a fact that this can be done without the carrier manipulating the data.. i just don't know how. As far as i recall on my old days of GSM.. the SMS can be manipulated (in a more hardcore point of view) by changing some details when on PDU mode (please check : http://www.smartposition.nl/resources/sms_pdu.html) which could be a task for the ATMEGA... and the sending could be done using the AT commands of the GSM modem. I have tried many times.. just for some reason i never was able to output the data.. so.. that project was taken to backside of the barn and shoot dead.

    But now... this new IDE just reminded me of that.. and.. oh well.. old habits are hard to let go i guess.. ^_^

    Just imagine a SMS distribution system implemented using an arduino.. a gsm modem (such as the shield on the topic above) .. and PDU manipulation code. I believe that many shop owners would like such an application... (specially because many carriers are giving free SMS on their plans).

    What do you guys think... ?

    Again.. sorry for the offtopic.. but i guess it maybe be a close fit..
     
  5. quique

    quique Member Licensed User

    Hi!

    Something most unusual had happened to me with this code: I downloaded it and successfully tried it "as is" a couple of days ago.

    Today, I decided to try it again, same code base, same boards, same gsm chip, etc. but adding a bit more of functionality:

    I added a DHT11 temp & humidity sensor on pin 4 and a solid relay on pin 6.

    The resulting code received SMS just fine but It refused to send SMS.

    After about an hour of debugging, I found the following:

    Inside the GSM.bas code, at the beginning of the SendSMS sub, the first line of code:

    Code:
    If busy Then Return False
    ... was triggering, thus shorting out the sub execution and returning with FALSE.

    I commented out that line of code and my program runs just fine sending SMS.

    For the life of me, I cannot detect HOW did I cause that to happen.

    I suspect something a bit more obscure may be happening: Could some other variable (perhaps one var also called "busy") at library level (specifically on the DHT library) mix up in some way?

    Below you will find my slighty customized code. There is also the GSM.bas code which has the conflictive line of code commented out.

    Code:
    Private Sub AppStart
    [INDENT]Serial1.Initialize(
    115200)
    Log("AppStart")
    GSM.Init(
    78)
    pip.Initialize( 
    "ledblink",1000)
    pip.Enabled=
    True
    DHT11pin.Initialize(
    4,DHT11pin.MODE_INPUT)   
    led.Initialize(2led.MODE_OUTPUT)
    btn.Initialize(
    3, btn.MODE_INPUT_PULLUP)
    btn.AddListener(
    "btn_StateChanged")
    rele.Initialize(
    6, rele.MODE_OUTPUT)[/INDENT]
    EndSub

    Sub ledblink()
    [INDENT]
    led.DigitalWrite(Not(led.digitalread)) [/INDENT]
    EndSub



    Sub btn_StateChanged (State As Boolean)
    [INDENT]
    If State = False Then
    [INDENT]GSM.SendSMS(phoneNumber, 
    "Click!!!")[/INDENT]
    EndIf[/INDENT]
    EndSub



    Sub MessageArrived(msg() As Byte)
    [INDENT]
    If msg = "On" Then
    [INDENT]rele.DigitalWrite(
    True)
    GSM.SendSMS(phoneNumber, 
    "On")[/INDENT]
    else if msg= "Off" Then
    [INDENT]rele.DigitalWrite(
    False)
    GSM.SendSMS(phoneNumber, 
    "Off")[/INDENT]
    else if msg= "Info" Then
    [INDENT]GSM.SendSMS(phoneNumber,dht11result)[/INDENT]
    Else
    [INDENT]
    Log("error: ", msg)[/INDENT]
    EndIf[/INDENT]
    EndSub



    Sub dht11result() As String
    [INDENT]
    Dim texto As String
    DHT11sensor.Read11(DHT11pin.PinNumber)            
    'Reading the DHT11 measure
    humidity=DHT11sensor.GetHumidity                'Get humidity from readed measure
    temperature=DHT11sensor.GetTemperature            'Get temperature from readed measure
    mytext= JoinStrings(Array As String("Humidity ",humidity,"% Temp ",temperature,"c"))[/INDENT]
    Return mytext
    EndSub
     
  6. Erel

    Erel Administrator Staff Member Licensed User

    No. A library variable cannot affect your variables. However it is possible that for some reason a task never completed which caused the busy flag to remain true.
     
  7. Tayfur

    Tayfur Well-Known Member Licensed User

    Hello @Erel & @rbghongade

    I recived my GPRS shield. it s same your shield.

    Connceted like under below. ( ı used diffrent rx tx port on shiled)

    GSM TX --->> Wemos D5
    GSM RX --->> Wemos D6
    GSM VCC 5V--->> Wemos 5V port
    GSM VCC gnd--->> Wemos GND port

    I cant recive data from Shield.
    "AStream_NewData" cant run.??? Please help me....

    Log...>>>
    ---APPStart
    ---sub init
    ---sub Eneblasmsevent
    ---sub sendcommand


    res1.jpg


    Code:
    Region Project Attributes
        
    #AutoFlushLogs: True
        
    #CheckArrayBounds: True
        
    #StackBufferSize: 1000
    #End Region

    Sub Process_Globals
        
    Public Serial1 As Serial
        
    Private led As Pin
        
    Private btn As Pin
        
    Private wemos As D1Pins
         
    Private Timer1 As Timer
         
    Private durum As Boolean
        
    Private phoneNumber As String = "+905331234567"
    End Sub

    Private Sub AppStart
        Serial1.Initialize(
    115200)
        
    Log("AppStart")
        
    'GSM.Init(7, 8)
        GSM.Init(wemos.D5, wemos.D6)
        
    led.Initialize(wemos.D2, led.MODE_OUTPUT)
        btn.Initialize(wemos.D3, btn.MODE_INPUT_PULLUP)
        btn.AddListener(
    "btn_StateChanged")
        Timer1.Initialize(
    "Timer1_Tick"20000'1000ms = 1 second
       Timer1.Enabled = True
       durum=
    False
    End Sub
    Private Sub Timer1_Tick
        
    Log(">>>Timer1")
        
    If durum = False Then
            GSM.SendSMS(phoneNumber, 
    "Click!!!")
            durum=
    True
        
    End If
    End Sub
    Sub btn_StateChanged (State As Boolean)
        
    If State = False Then
            GSM.SendSMS(phoneNumber, 
    "Click!!!")
        
    End If
    End Sub

    Sub MessageArrived(msg() As Byte)
        
    If msg = "On" Then
            
    led.DigitalWrite(True)
        
    Else if msg = "Off" Then
            
    led.DigitalWrite(False)
        
    Else
            
    Log("error: ", msg)
        
    End If
    End Sub
     
  8. rbghongade

    rbghongade Active Member Licensed User

    You have not declared/initialized asyncstream object. Hence the event is not triggered.
     
  9. Tayfur

    Tayfur Well-Known Member Licensed User

    thank you for feedback.

    I used same code GSM example files in message #1 (erels eample)

    I cant recie data from gsm. Where is problem??

    Code:
    Region Project Attributes
        
    #AutoFlushLogs: True
        
    #CheckArrayBounds: True
        
    #StackBufferSize: 1000
    #End Region
    '****** MAIN   MODULE****************
    Sub Process_Globals
        
    Public Serial1 As Serial
        
    Private led As Pin
        
    Private btn As Pin
        
    Private wemos As D1Pins
         
    Private Timer1 As Timer
         
    Private durum As Boolean
        
    Private phoneNumber As String = "+905331234567"
    End Sub

    Private Sub AppStart
        Serial1.Initialize(
    115200)
        
    Log("AppStart")
        
    'GSM.Init(7, 8)
        GSM.Init(wemos.D5, wemos.D6)
        
    led.Initialize(wemos.D2, led.MODE_OUTPUT)
        btn.Initialize(wemos.D3, btn.MODE_INPUT_PULLUP)
        btn.AddListener(
    "btn_StateChanged")
        Timer1.Initialize(
    "Timer1_Tick"20000'1000ms = 1 second
       Timer1.Enabled = True
       durum=
    False
    End Sub
    Private Sub Timer1_Tick
        
    Log(">>>Timer1")
        
    If durum = False Then
            GSM.SendSMS(phoneNumber, 
    "Click!!!")
            durum=
    True
        
    End If
    End Sub
    Sub btn_StateChanged (State As Boolean)
        
    If State = False Then
            GSM.SendSMS(phoneNumber, 
    "Click!!!")
        
    End If
    End Sub

    Sub MessageArrived(msg() As Byte)
        
    If msg = "On" Then
            
    led.DigitalWrite(True)
        
    Else if msg = "Off" Then
            
    led.DigitalWrite(False)
        
    Else
            
    Log("error: ", msg)
        
    End If
    End Sub

    Code:
    '********  GMS  MODULE ****************
    Sub Process_Globals
        
    Private serial As SoftwareSerial
        
    Private bc As ByteConverter
        
    Private astream As AsyncStreams
        
    Private EOL() As Byte = Array As Byte(13)
        
    Private busy As Boolean
        
    Private messageToSend(160As Byte
        
    Private SMSSlot(4As Byte
        
    Private retryEmptyMessages As Byte
    End Sub

    Public Sub Init(rx As Byte, tx As Byte)
        
    serial.Initialize(9600, rx, tx)
        astream.Initialize(
    serial.Stream, "astream_NewData"Null)
        astream.WaitForMoreDataDelay = 
    100 'make sure that we receive full messages
        busy = False
        EnableSMSEvents
    End Sub


    Public Sub EnableSMSEvents As Boolean
        
    Return SendCommand("AT+CNMI=2,1"True)
    End Sub

    'PhoneNumber - should start with + and include country code.
    Public Sub Call (PhoneNumber() As Byte) As Boolean
        
    If busy Then Return False
        busy = 
    True
        astream.Write(
    "ATD").Write(PhoneNumber).Write(";").Write(EOL)
        
    Return True
    End Sub

    'PhoneNumber - should start with + and include country code.
    Public Sub SendSMS(PhoneNumber() As Byte, message() As Byte) As Boolean
        
    If busy Then Return False
        busy = 
    True
        astream.Write(
    "AT+CMGS=""").Write(PhoneNumber).Write("""").Write(EOL)
        
    'copy the message to the global variable
        bc.ArrayCopy(message, messageToSend)
        
    Return True
    End Sub

    Private Sub SendSMSPart2
        busy = 
    True
        astream.Write(messageToSend).Write(
    Array As Byte(0x1a))
    End Sub

    Private Sub SendSMSPart3
        
    Log("Message was sent successfully")
    End Sub

    Public Sub Hangup As Boolean
        
    Return SendCommand("ATA"False)
    End Sub

    Private Sub SendCommand (cmd() As Byte, ResponseExpected As Boolean) As Boolean
        
    If busy Then Return False
        busy = ResponseExpected
        astream.Write(cmd).Write(EOL)
        
    Return True
    End Sub

    Public Sub CheckRegistered
        SendCommand(
    "AT+CREG?"True)
    End Sub

    Private Sub CheckRegisteredResult (buffer() As Byte)
        
    If bc.IndexOf(buffer, "+CREG: 0,1") > -1 Or bc.IndexOf(buffer, "+CREG: 0,5") > -1 Then
            
    Log("Registered")
        
    Else
            
    Log("Not registered")
        
    End If
    End Sub

    Private Sub SMSArrived1(buffer() As Byte)
        
    Dim i As Int = bc.IndexOf(buffer, ","
        
    Dim slot() As Byte = bc.SubString(buffer, i + 1)
        bc.ArrayCopy(slot, SMSSlot)
        
    Log("SMS received, slot = ", SMSSlot)
        retryEmptyMessages = 
    0
        Delay(
    200)
        astream.Write(
    "AT+CMGR=").Write(slot).Write(EOL)
        busy = 
    True
    End Sub

    Private Sub SMSArrived2(Buffer() As Byte)
        busy = 
    True
        
    Dim afterCMGR As Boolean = False
        
    Dim emptyMessage As Boolean = True
        
    'Log("buffer: ", Buffer)
        For Each line() As Byte In bc.Split(Buffer, Array As Byte(1310))
            
    If afterCMGR Then
                
    If line.Length = 0 Or bc.StartsWith(line, "OK"Then Continue
                
    Log("Msg: ", line)
                
    If emptyMessage Then
                    Main.MessageArrived(line)
                    emptyMessage = 
    False
                
    End If
            
    Else If bc.StartsWith(line, "+CMGR"Then
                
    Dim counter As Int = 0
                
    For Each s() As Byte In bc.Split(line, """")
                    
    If counter = 3 Then
                        
    Log("From: ", s)
                    
    Else If counter = 7 Then
                        
    Log("Date: ", s)
                    
    End If
                    counter = counter + 
    1
                
    Next
                afterCMGR = 
    True
            
    End If
        
    Next
        
    If emptyMessage And retryEmptyMessages < 3 Then
            retryEmptyMessages = retryEmptyMessages + 
    1
            
    Log("Trying to read message again.")
            Delay(
    200)
            astream.Write(
    "AT+CMGR=").Write(SMSSlot).Write(EOL)
        
    Else
            
    'delete the SMS
            astream.Write("AT+CMGD=").Write(SMSSlot).Write(EOL)
        
    End If
    End Sub

    Private Sub Ring(Buffer() As Byte)
        
    Dim clip() As Byte = "+CLIP: """
        
    Dim callingNumber() As Byte = "unknown"
        
    Dim i1 As Int = bc.IndexOf(Buffer, clip)
        
    If i1 > -1 Then
            
    Dim i2 As Int = bc.IndexOf2(Buffer, """", i1 + clip.Length)
            
    If i2 > -1 Then
                callingNumber = bc.SubString2(Buffer, i1 + clip.Length, i2)
            
    End If
        
    End If
        
    Log("Ring... Number: ", callingNumber)
        
    'hangup up the call
        Hangup
    End Sub

    Sub AStream_NewData (Buffer() As Byte)
        busy = 
    False
        
    Select True
            
    Case bc.IndexOf(Buffer, "+CREG:") > -1
                CheckRegisteredResult(Buffer)
            
    Case bc.IndexOf(Buffer, "RING") > -1
                Ring(Buffer)
            
    Case bc.IndexOf(Buffer, "AT+CMGS") > -1
                SendSMSPart2
            
    Case bc.IndexOf(Buffer, "+CMGS:") > -1
                SendSMSPart3
            
    Case bc.IndexOf(Buffer, "+CMTI:") > -1
                SMSArrived1(Buffer)
            
    Case bc.IndexOf(Buffer, "+CMGR:") > -1
                SMSArrived2(Buffer)
            
    Case Else
                
    Log("****************")
                
    Log(Buffer)
        
    End Select
    End Sub
     
  10. Tayfur

    Tayfur Well-Known Member Licensed User

    @Erel;
    please; could you share wire schema of GPRS Shiled-Arduino for ypur project.
     
  11. Tayfur

    Tayfur Well-Known Member Licensed User

    @Erel
    İ fixed some problems.

    [​IMG]
    http://www.geeetech.com/wiki/index.php/Arduino_GPRS_Shield

    I used for RX + TX + GND pins on UARTof SIM900 .

    Now I reading GPRS shileds.
    Stage 1 complated.

    (I cant understand otherher pins connections for your Sample)

    I recived SMS. but it s PDU format. is it normal? can i recive text format?


    Stage 2. SENDING SMS
    Your code runs...
    1. sub sendsms (ok)
    2. sub AstreamNewData (>> returnde data..2 lines.)
        • AT+CMGS="+905321111111"
        • ERROR
    3. sub SendSmsPart2 (ok)
    4. sub AstreamNewData (>>> returned data...
    • click!!!
    and waiting code....
    Where is problem? I cant recive error or data?
     
    Last edited: Nov 19, 2016
  12. Erel

    Erel Administrator Staff Member Licensed User

    Tayfur likes this.
  13. Tayfur

    Tayfur Well-Known Member Licensed User

    EYVALLAH KARDEŞİM SAOL. DENEDİM ÇALIŞTI. SIKINTI GÖZÜKMÜYOR ŞİMDİİLİK.
    MSJ GİDİYOR GELİYOR, ARTIK GERİSİ FANTEZİ KISMINI KALDI. BİRDE DEVLETİM SAĞOLSUN HEMEN IMEI NUMARASINI KAYDET DİYE MSJ ATTI :)

    YAKINDA BİR BANANA Pİ SİPARİŞİ VERİCEM, ORDA TAKILIRRSAM KAPINI ÇALARIM
     
  14. Tayfur

    Tayfur Well-Known Member Licensed User

    Erel likes this.
  15. ta1dr

    ta1dr Member Licensed User

    why delete my message ? some people write native language... :(
     
  16. Erel

    Erel Administrator Staff Member Licensed User

    There are sub-forums for non-English languages. If you like I can open a Turkish sub-forum.

    In all other forums you should only write in English as there are many members from all over the world reading these posts.
     
  17. ta1dr

    ta1dr Member Licensed User

    Hi Erel
    Thanks for information
     
  18. Tayfur

    Tayfur Well-Known Member Licensed User

    could you share full project? (I need other pins actions.)
     
  19. Erel

    Erel Administrator Staff Member Licensed User

    The project is attached to the first post.
     
  20. Tayfur

    Tayfur Well-Known Member Licensed User

    I cheked your sample; But, your code has not D9 pins actions or Analog Pins actions.
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice