You are here:
ActiveXperts.com > SMS Messaging Server > Case Studies > Hotradio SMS Song Voting System
Quicklinks
HotRadio is a non-commercial radio station. It has been broadcasting since 1998 and plays a wide variety of popular music. It is on air 24 hours a day, 7 days a week on the FM frequency and on the Internet. HotRadio has a wide variety of programs, from non-stop music programs to news programs.
This case study discusses two popular services available with HotRadio
To run both services there's a panel of two people who accept calls from listeners who either want to request a song or want to play the game and try to win a price.
This system has some drawbacks:
The current phone system must be replaced by a new, more efficient system. Goals of the new system:
The HotRadio team decided to replace their current system where the activities of both panel members where completely automated.
HotRadio reserved two numbers for SMS messages, for this example we will use: +31638740160 and +31638740161. Request for songs can be sent to +31638740160. Listeners can send 'Play and Win' answers to +31638740161.
On the 'Play and Win' number, any SMS message is accepted, because the answer to the question can be anything.
On 'We Play Your Music', the SMS message must match a predefined message format. If listeners do not know the message format, they can send a help command ('?') to ask for the message syntax. The system will reply and tell the listener what message syntax to use.
The system handles SMS messages as follows:
| SMS Number | SMS message body (syntax) | Sample | Description |
|---|---|---|---|
| +31638740160 ('We Play Your Music') |
Vote [1-1000] | Vote 114 | Vote for a song. In this sample, the listener sends a request for song 114 |
| ? | ? | Help command. A Help message is returned to the listener | |
| <blanc> | Unrecognized command. A Help message is returned to the listener | ||
| +31638740161 ('Play and Win') |
<any message> | This is my answer to the question on Play and Win | Answer to the question of the Play and Win item |
| <blanc> | Blanc answers are not accepted. A Help message is returned to the listener |
The system consists of the following:
HotRadio had to choose out of two SMS communication techniques: SMPP or GSM modem. Since SMPP is designed for high volume SMS messaging (hundreds of SMS messages per hour) this would be a lot more than what they need. The GSM modem throughput (10 messages per minute) is sufficient and more economical for this solution. To have both phone numbers available they needed to purchase two modems which they needed to fit with two SIM cards with corresponding SMS bundles.
There are two databases involved:
WePlayYourMusic, SongTitles table:
WePlayYourMusic, SongRequests table:
A Trigger is called when a new messages arrives in the system. HotRadio only accepts messages via SMS. Since HotRadio uses two different incoming SMS numbers with two different SMS number, two triggers are defined. One trigger for incoming messages on +31638740160 'We Play Your Music' and one trigger for incoming messages on +31638740160 'Play and Win'.
| Enabled | Description | Condition | Script |
|---|---|---|---|
| YES | Process incoming song requests | To = '+31638740160' | \Projects\HotRadio Radio Station\Triggers\WePlayYourMusic.vbs |
| YES | Process incoming answers | To = '+31638740161' | \Projects\HotRadio Radio Station\Triggers\PlayAndWin.vbs |
Each trigger will be called for every new incoming message, as long as the condition is matched.
The WePlayYourMusic.vbs trigger does the following in pseudo code:
- Set incoming message to 'processed', so it will not be processed again by the system
- If message is empty => send an SMS reply to the listener that message
is not accepted
- If message is a valid song request => Update the SongRequests table in the
WePlayYourMusic.mdb, send an SMS reply to the
listener with the number of votes for that song
and total number of votes
- If message is not a valid song request => send an SMS reply to the listener that message
is not accepted
The PlayAndWin.vbs trigger does the following:
- Set incoming message to 'processed', so it will not be processed again by the system
- If message is empty => send an SMS reply to the listener that answer
is not accepted
- Any other message => Update the Answers table in the PlayAndWin.mdb
database, send an SMS reply to the listener
that answer has been processed.
- If message is not a valid song request => send an SMS reply to the listener that message
is not accepted
Option Explicit
CONST STR_WEPLAYYOURMUSICDBFILE = "Projects\HotRadio Radio Station\Database\WePlayYourMusic.mdb"
CONST STR_DEBUGFILE = "Tmp\WePlayYourMusic.txt"
CONST STR_USAGE = "To send a request, type: Vote [1-1000]"
Dim g_objMessageDB, g_objDebugger, g_objConstants
' Creation of global objects
Set g_objConstants = CreateObject( "Axsms-messaging-server.Constants" )
Set g_objMessageDB = CreateObject( "Axsms-messaging-server.MessageDB" )
Set g_objDebugger = CreateObject( "ActiveXperts.VbDebugger" )
' Set Debug file
g_objDebugger.DebugFile = STR_DEBUGFILE
' // ========================================================================
' // ProcessMessage
' // ------------------------------------------------------------------------
' // ProcessMessage trigger function
' // ========================================================================
Function ProcessMessage( numMessageID )
Dim objMessageIn, objMessageOut, arrMessage
Dim strMessageOutBody
Dim numSongID, strCommand
g_objDebugger.WriteLine ">> ProcessMessage"
' Open the message database
g_objMessageDB.Open
If( g_objMessageDB.LastError <> 0 ) Then
g_objDebugger.WriteLine "<< ProcessMessage, unable to open database"
Exit Function
End If
' Retrieve the message that has just been received. If it fails then exit script
Set objMessageIn = g_objMessageDB.FindFirstMessage( "ID = " & numMessageID )
If g_objMessageDB.LastError <> 0 Then
g_objMessageDB.Close
g_objDebugger.WriteLine "<< ProcessMessage, unable to find message"
Exit Function
End If
' Set incoming SMS message status to: SUCCESS (previous state was: PENDING)
objMessageIn.Status = g_objConstants.MESSAGESTATUS_SUCCESS
g_objMessageDB.Save objMessageIn
g_objDebugger.WriteLine " Incoming message saved, result: [" & g_objMessageDB.LastError & "]"
' Split received message body into pieces (separated by spaces)
arrMessage = Split( UCase( objMessageIn.Body ), " " )
If( UBound( arrMessage ) = 0 ) Then
' Just 1 param, so ? is expected. But on any other single word, also show help
strMessageOutBody = ShowHelp()
ElseIf( UBound( arrMessage ) = 1 ) Then
strCommand = GetCommand( arrMessage(0) ) ' Converts any word starting with v or V to V
numSongID = GetSongID( arrMessage(1) ) ' Converts string to number, if possible.
If( strCommand <> "V" ) Then
strMessageOutBody = ShowWrongParam( arrMessage(0) )
ElseIf( numSongID = 0 ) Then
strMessageOutBody = ShowWrongParam( arrMessage(1) )
Else
strMessageOutBody = UpdateSongRequests( objMessageIn.Sender, numSongID )
End If
Else
strMessageOutBody = ShowSyntaxError()
End If
' Create a new reply message
Set objMessageOut = g_objMessageDB.Create
g_objDebugger.WriteLine " New message created, result: [" & g_objMessageDB.LastError & "]"
If( g_objMessageDB.LastError = 0 ) Then
objMessageOut.Direction = g_objConstants.MESSAGEDIRECTION_OUT
objMessageOut.Type = g_objConstants.MESSAGETYPE_SMS
objMessageOut.Status = g_objConstants.MESSAGESTATUS_PENDING
objMessageOut.To = objMessageIn.From
objMessageOut.ChannelID = objMessageIn.ChannelID ' Use the incoming message channel
objMessageOut.Body = strMessageOutBody
g_objMessageDB.Save objMessageOut
g_objDebugger.WriteLine " New message saved, result: [" & g_objMessageDB.LastError & "]"
End If
g_objDebugger.WriteLine "<< ProcessMessage"
End Function
' // ========================================================================
' // UpdateSongRequests
' // ------------------------------------------------------------------------
' // Update the SongRequests table with the request that was just received
' // ========================================================================
Function UpdateSongRequests( strSenderNumber, numSongID )
On Error Resume Next
Dim objConn, strQuery, RS, hexError, strResult
Dim cnt1, cnt2
Dim strSong
g_objDebugger.WriteLine( ">> UpdateSongRequests( " & strSenderNumber & "," & numSongID & ")" )
' Create database object; open the database
Set objConn = CreateObject("ADODB.Connection")
objConn.Open "Driver={Microsoft Access Driver (*.mdb)}; DBQ=" & STR_WEPLAYYOURMUSICDBFILE & ";"
' Retrieve Song title, to display it later in the reply
' If it does not exist then return with an error
strQuery = "SELECT * FROM SongTitles WHERE ID=" & numSongID
Err.Clear ' Clear a previous error
Set RS = objConn.Execute( strQuery )
hexError = Hex( Err.Number )
If( hexError <> "0" ) Then
g_objDebugger.WriteLine( "<< UpdateSongRequests, Err.Number: " & Err.Number )
UpdateSongRequests = "Request could not be processed (database error #" & _
hexError & " occured ). "
objConn.Close
Set objConn = Nothing
Exit Function
End If
If( RS.EOF ) Then
g_objDebugger.WriteLine( "<< UpdateSongRequests, song does not exist" )
UpdateSongRequests = "Request could not be processed (song #" & _
numSongID & " does not exist). "
objConn.Close
Set objConn = Nothing
Exit Function
End If
strSong = RS( "Artist" ) & "-" & RS( "Title" )
strSong = Trim( strSong )
' Execute INSERT statement
strQuery = "INSERT INTO SongRequests( SmsNumber, DateVal, TimeVal, SongID ) VALUES ( '" & _
strSenderNumber & "', '" & Date() & "', '" & Time() & "', " & numSongID & " )"
Err.Clear ' Clear a previous error
objConn.Execute( strQuery )
' Catch error - if any
hexError = Hex( Err.Number )
If( hexError <> "0" ) Then
g_objDebugger.WriteLine( "Err.Number: " & Err.Number & "; Err.Description: " & _
Err.Description )
UpdateSongRequests = "Request could not be processed. "
objConn.Close
Set objConn = Nothing
Exit Function
End If
strResult = "Request successfully processed. "
' Now, calculate #request for this particular song (cnt1) and totla requests(cnt2).
' If both can be calculated then append it to the reponse
cnt1 = 0
cnt2 = 0
strQuery = "Select Count(*) As cnt1 FROM SongRequests WHERE SongID = " & numSongID
g_objDebugger.WriteLine( strQuery )
Set RS = objConn.Execute( strQuery )
hexError = Hex( Err.Number )
If( hexError = "0" ) Then
cnt1 = RS( "cnt1" )
strQuery = "Select Count(*) As cnt2 FROM SongRequests"
Set RS = objConn.Execute( strQuery )
hexError = Hex( Err.Number )
If( hexError = "0" ) Then
cnt2 = RS( "cnt2" )
strResult = strResult & "#Votes for [" & strSong & "]: " & cnt1 & "; #Total Votes: " & _
cnt2
End If
End If
objConn.Close
Set objConn = Nothing
UpdateSongRequests = strResult
g_objDebugger.WriteLine( "<< UpdateSongRequests, result: " & UpdateSongRequests )
End Function
' // ========================================================================
' // Show... functions
' // ------------------------------------------------------------------------
' // Some error handling Show errors
' // ========================================================================
Function ShowWrongParam( strParam )
ShowWrongParam = "Wrong parameter: " & strParam
End Function
Function ShowWrongCommand( strCommand )
ShowWrongCommand = "Wrong command: " & strCommand
End Function
Function ShowSyntaxError()
ShowSyntaxError = "Syntax error. " & STR_USAGE
End Function
Function ShowHelp()
ShowHelp = STR_USAGE
End Function
' // ========================================================================
' // GetCommand
' // ------------------------------------------------------------------------
' // Get the command. The only supported command is: Vote (or 'V' or 'V', or
' // anything else that starts with 'v'
' // ========================================================================
Function GetCommand( strCommand )
Dim strUCommand
g_objDebugger.WriteLine( ">> GetCommand ( " & strCommand & " )" )
GetCommand = ""
strUCommand = UCase( strCommand )
If( Left( strUCommand, 1 ) <> "V" ) Then
GetCommand = ""
g_objDebugger.WriteLine( "<< GetCommand, first character is not a 'v' or 'V'" )
Exit Function
End If
GetCommand = "V"
g_objDebugger.WriteLine( "<< GetCommand, return: V" )
End Function
' // ========================================================================
' // GetSongID
' // ------------------------------------------------------------------------
' // Function returns the song ID.
' // If paramter cannot be ocnverted to a number, or if number not in
' // range [1..1000] then 0 is returned
' // ========================================================================
Function GetSongID( strSongID )
On Error Resume Next ' Necessary to catch error because of a non-numeric value
Dim numSongID
g_objDebugger.WriteLine( ">> GetSongID ( " & strSongID & " )" )
numSongID = 0 ' do this because next call may fail upon non-integer
numSongID = CInt( strSongID )
If( numSongID = 0 ) Then
GetSongID = 0
Exit Function
End If
If( numSongID < 1 Or numSongID > 1000 ) Then
GetSongID = 0
Exit Function
End If
GetSongID = numSongID
g_objDebugger.WriteLine( "<< GetSongID, return: " & numSongID )
End Function
' // ======================================================================== ' // PlayAndWin.vbs ' // ------------------------------------------------------------------------ ' // HotRadio Case Study ' // For more details, go to www.activexperts.com/sms-messaging-server/casestudies/hotradio ' // ======================================================================== Option Explicit CONST STR_PLAYANDWINDBFILE = "Projects\HotRadio Radio Station\Database\PlayAndWin.mdb" CONST STR_DEBUGFILE = " Tmp\PlayAndWin.txt" CONST STR_USAGE = "Type the answer of the question in the body of the message" Dim g_objMessageDB, g_objConstants, g_objDebugger ' Creation of global objects Set g_objConstants = CreateObject( "Axsms-messaging-server.Constants" ) Set g_objMessageDB = CreateObject( "Axsms-messaging-server.MessageDB" ) Set g_objDebugger = CreateObject( "ActiveXperts.VbDebugger" ) ' Set Debug file g_objDebugger.DebugFile = STR_DEBUGFILE ' // ======================================================================== ' // ProcessMessage ' // ------------------------------------------------------------------------ ' // ProcessMessage trigger function ' // ======================================================================== Function ProcessMessage( numMessageID ) Dim strMessageOutBody, objMessageIn, objMessageOut Dim numSongID, strCommand g_objDebugger.WriteLine ">> ProcessMessage" ' Open the message database g_objMessageDB.Open If( g_objMessageDB.LastError <> 0 ) Then g_objDebugger.WriteLine "<< ProcessMessage, unable to open database" Exit Function End If ' Retrieve the message that has just been received. If it fails then exit script Set objMessageIn = g_objMessageDB.FindFirstMessage( "ID = " & numMessageID ) If g_objMessageDB.LastError <> 0 Then g_objMessageDB.Close g_objDebugger.WriteLine "<< ProcessMessage, unable to find record" Exit Function End If ' Set incoming SMS message status to: SUCCESS (previous state was: PENDING) objMessageIn.Status = g_objConstants.MESSAGESTATUS_SUCCESS g_objMessageDB.Save objMessageIn g_objDebugger.WriteLine "Incoming message saved, result: [" & g_objMessageDB.LastError & "]" If( Len( Trim( objMessageIn.Body ) ) <= 0 ) Then strMessageOutBody = ShowHelp() Else strMessageOutBody = AddAnswer( objMessageIn.Sender, objMessageIn.Body ) End If ' Create a new reply message Set objMessageOut = g_objMessageDB.Create g_objDebugger.WriteLine "New message created, result: [" & g_objMessageDB.LastError & "]" If( g_objMessageDB.LastError = 0 ) Then objMessageOut.Direction = g_objConstants.MESSAGEDIRECTION_OUT objMessageOut.Type = g_objConstants.MESSAGETYPE_SMS objMessageOut.Status = g_objConstants.MESSAGESTATUS_PENDING objMessageOut.To = objMessageIn.From objMessageOut.ChannelID = objMessageIn.ChannelID ' Use the incoming message channel. objMessageOut.Body = strMessageOutBody g_objMessageDB.Save objMessageOut g_objDebugger.WriteLine " New message saved, result: [" & g_objMessageDB.LastError & "]" End If ' Close the Database g_objMessageDB.Close g_objDebugger.WriteLine "<< ProcessMessage" End Function ' // ======================================================================== ' // AddAnswer ' // ------------------------------------------------------------------------ ' // Adds the answer to the PlayAndWin.mdb-Answers table ' // ======================================================================== Function AddAnswer( strSenderNumber, strAnswer ) On Error Resume Next Dim objConn, strQuery, RS, hexError g_objDebugger.WriteLine( ">> AddAnswer( " & strSenderNumber & "," & strAnswer & ")" ) ' Create database object; open the database Set objConn = CreateObject("ADODB.Connection") objConn.Open "Driver={Microsoft Access Driver (*.mdb)}; DBQ=" & STR_PLAYANDWINDBFILE & ";" ' Execute INSERT statement strQuery = "INSERT INTO Answers( SmsNumber, DateVal, TimeVal, Answer ) VALUES ( '" & _ strSenderNumber & "', '" & Date() & "', '" & Time() & "', '" & strAnswer & "' )" Err.Clear ' Clear a previous error objConn.Execute( strQuery ) ' Catch error - if any hexError = Hex( Err.Number ) If( hexError <> "0" ) Then g_objDebugger.WriteLine( "Err.Number: " & Err.Number & "; Err.Description: " & _ Err.Description ) AddAnswer = "Answer could not be processed. " objConn.Close Set objConn = Nothing Exit Function End If AddAnswer = "Answer successfully processed." objConn.Close Set objConn = Nothing g_objDebugger.WriteLine( "<< AddAnswer, result: " & AddAnswer) End Function ' // ======================================================================== ' // Show... functions ' // ------------------------------------------------------------------------ ' // Some error handling Show errors ' // ======================================================================== Function ShowHelp() ShowHelp = STR_USAGE End Function