12 months ago on our flight home from the 2012 Mastering SAP Technologies we were reflecting on the demo jam contest and wondered what we would need to in order to win the following year... We decided that the only think that we could win, in a room that we mostly full of men drinking beer, was to build an air cannon and then retrofit some technology...and so the concept began to take shape!
Fast forward to March 2013, and our concept was not only born but won!! Big thanks to my colleagues for all their work - John Schultz (Think180) and Abhinav Tayal.
Here's the concept (I'll cover the technology a bit later)....
The whole premise for our concept was to demonstrate that you can do so much with what your already own as part of your SAP ERP system. You don't need to go and buy other tools or take on additional licensing to do some pretty clever things.
Our solution was totally controlled by our cloud based ERP System. The system is not all that current is actually is a quite a few Enhancement Packs behind.
How we built it and all the pieces...
Step 1 & 2 - Sending & Receiving SMS
To send an receive SMS messages from SAP, we used a SOAP based web service from a large Australian SMS provider called Message Media (message-media.com.au) who we've worked with in the past. We helped them a few years ago to setup their service to fully consumable from an ABAP system) We setup an acount which also included an incoming number that allowed messages to be routed to our account.
We consumed their WSDL in SE80 to create a client proxy - http://soap.m4u.com.au/2010/service.wsdl . Its that easy
The Message Media web service has a number of methods but we're only interested in the send and receive methods.
Once we had the service consumed, we needed to put together a quick SMS Class that will allow us to perform the sending and receiving. We called the class ZCL_SMS. The outline of the class is below:
This method process all the responses from the audience.
method receive.
data: ls_response like line of gt_response.
data: lo_message type ref to zmmco_message_media_service_in .
data: check_replies_response type zmmcheck_replies_response .
data: check_replies_request type zmmcheck_replies_request .
data: lv_message type string,
lv_name type string,
lv_register type string,
lt_recips type stringtab,
lv_recip like line of lt_recips,
lt_receipts type zmmconfirm_item_type_tab,
ls_receipt like line of lt_receipts.
field-symbols: <ls_response> like line of check_replies_response-parameters-result-replies-reply.
try.
create object lo_message.
catch cx_ai_system_fault . "#EC NO_HANDLER
endtry.
* Build authenticaion
me->build_authentication( importing ev_password = check_replies_request-parameters-authentication-password
ev_uname = check_replies_request-parameters-authentication-user_id ).
try.
call method lo_message->check_replies
exporting
check_replies_request = check_replies_request
importing
check_replies_response = check_replies_response.
loop at check_replies_response-parameters-result-replies-reply assigning <ls_response>.
ls_response-phoneno = <ls_response>-origin.
ls_response-name = <ls_response>-content.
* remove spaces
condense ls_response-name.
* TRANSLATE ls_response-response TO UPPER CASE.
append ls_response to rt_response.
* SET RESPONSE TO PROCESSED.
ls_receipt-receipt_id = <ls_response>-receipt_id.
append ls_receipt to lt_receipts.
endloop.
if lt_receipts is not initial.
call method me->confirm_response
exporting
it_receipts = lt_receipts.
endif.
catch cx_root . "#EC NO_HANDLER
endtry.
endmethod.
As we process the responses from the audience, we'll store them in a database table with a unique GUID for processing. We send a message straight back advising that we've received their registration.
Method send.
data: lx_error type ref to cx_root,
ls_message type zmmmessage_type,
lv_error type string,
ls_recipient like line of ls_message-recipients-recipient.
data: lo_message type ref to ZMMCO_MESSAGE_MEDIA_SERVICE_IN.
data: send_messages_response type zmmsend_messages_response .
data: send_messages_request type zmmsend_messages_request .
field-symbols: <ls_recipient> like line of lt_recipients.
try.
create object lo_message.
catch cx_ai_system_fault . "#EC NO_HANDLER
endtry.
* Build authenticaion
me->build_authentication( importing ev_password = send_messages_request-parameters-authentication-password
ev_uname = send_messages_request-parameters-authentication-user_id ).
* Build Messages.
* ls_message-scheduled = .
* ls_message-delivery_report = abap_true.
ls_message-validity_period = '169'.
ls_message-format = 'SMS'.
ls_message-content = iv_message.
* Build recipients.
loop at lt_recipients assigning <ls_recipient>.
ls_recipient-value = <ls_recipient>.
* ls_recipient-uid = <ls_msg_itm>-networkuid.
append ls_recipient to ls_message-recipients-recipient.
clear ls_recipient.
endloop.
* add message
append ls_message to send_messages_request-parameters-request_body-messages-message.
try.
call method lo_message->send_messages
exporting
send_messages_request = send_messages_request
importing
send_messages_response = send_messages_response.
catch cx_root into lx_error.
lv_error = lx_error->get_text( ).
* <ls_msg_itm>-msg_status = /etsa/cl_push_message=>gc_msg_error.
endtry.
endmethod.
Step 3 - Processing Respondents
To give each person a chance to select their angle and fire the cannon (one at a time), we built a Web Dynpro Screen (below). The phone number of the row selected was 'active'. As soon as we selected a row (made the line active), we triggered an SMS message with the URL of the cannon BSP. We just re-used our SMS class with a different message.
The web dynpro above was just a simple table control that read the respondents from our database table and sorted them in order of received date and time. We also included a timer control to trigger automatic refreshes every 30 seconds. The SMS with the link to the BSP was triggered by the lead select event on the table control. The message we sent is below:
Step 4 - BSP Page
Once the respondent gets the SMS with the link on their phone they can click on the link to access our BSP page to select their preferred angle and fire. Our BSP page uses HTML5. The page contains a cannon image that can used move up and down depending on the phone's orientation. Check out the page below:
We had a lot of trouble trying to get restrict the movement of cannon so that it would only move between 90 degree and 30 degree. We only allowed the web page to be viewed in landscape mode. The fire event on the BSP triggered a call to our cannon to move and fire through an ajax javascript call via an HTTP GET. We tried quite a few methods of executing the HTTP call to the cannon using approaches such as SM59, ajax etc and found SM59 was too slow and too slow to time-out if there was error.
Step 5 - The Cannon
We designed and built the air cannon from scratch using the following materials:
Once all the parts had been purchased, the mechanics of the cannon were put together one evening. Adding the electronics and the integration to SAP was far more complex!
To move the cannon we developed a REST service on our embedded web server. We basically needed the service to process 3 parameters:
The REST service executed the code that we'd developed using SPIN and deployed on the Propeller chip. The deployed SPIN code was responsible for telling the stepper motor how to move and in what increments. Additionally, the SPIN code also executed the fire command on the solenoid.
Our electronics and team member John Schultz was responsible for all the electronics and programming of the chip...nice work John!!
Our embedded web server was connected to our wireless router via Ethernet to form a small LAN. The REST service and associated electronics worked beautifully from our local cannon network (192.168.158.x) but the web server had to accessible from the internet as our SAP system is located outside of our cannon network (internet). In testing, all was working well in our Think180 office as we'd setup a port forward on our office based ADSL router to the embedded web server. However, demo jam was not going to be at our office and so we had to have a portable internet access...mobile broadband.
In hindsight the most complex component of the solution was getting our SAP system to be able to execute the REST service on our embedded web server using a mobile broadband internet connection. To be able to access the web server, we either needed a static IP on the mobile broadband or the ability to assign dynamic DNS. We now know that most mobile broadband provides in Australia (eg Telstra, Optus etc) NAT their mobile services meaning that they can't be used for remote access. Problem solved when we found a local and very well respected ISP (Internode) that had cheap prepaid mobile broadband with static IPs...thank goodness and we thought we were sunk!
When it came togather, the cannon fired small runner tennis balls from the local pet shop (as you can see in the photo above).
Amazingly, all the pieces came together and worked beautifully on the day. Email me if you would like any more details on any of the pieces - stephen.silver@think180.com.au