Tagged: raspberry pi

Raspberry Pi + MakeyMakey + Scratch = Fruit & Veg interface

I recently got a MakeyMakey. It's a sort of ersatz USB keyboard that can be plugged into anything electrically conductive.

So, I plugged it into my Raspberry Pi, loaded up the Scratch programming environment, and created a fruit and veg interface. See for yourself!

The scripts themselves are very simple.
Scratch Fruit and Veg Keyboard
The MakeyMakey in its default state, acts like a USB keyboard - so it will send up, down, left, right, and the space key. So, it's really easy to use with Scratch's "Key ___ Pressed" sensor.

Download Scratch from MIT (available for Linux, Windows, Mac).

You can grab yourself a Raspberry Pi on Amazon

You can buy a MakeyMakey from Amazon for around £40

You can buy bananas and spring onions from any reputable green-grocer. Be sure to ask if they're electrically conductive.

Thanks to the OpenRightsGroup for sending me the MakeyMakey.

The Future of Internet Services

There's a cyclic nature to technology development. What starts small and personal, becomes big until - inevitably - it becomes small again. Then the cycle repeats.

All this has happened before...

We started with mainframes on which we had to time-slice. Then we got powerful personal computers. Now we're back to spooling up instances of cloud computers.

...and all this will happen again

We used to have individual websites. Upon which we ran whatever services we wanted - mail, FTP, finger, anything.

Where are we now? We run these services - or similar - on mainframes. Whether it's Facebook, MySpace, Instagram, or Path - we're back to storing all our data and connections with 3rd parties.

Into The Future With Confidence!

At the moment we're stuck in an era of restricted data portability. Theoretically we can extract our data from Twitter et al - but we're totally at the mercy of those who run the services.

Compare Twitter to Email. If Twitter goes down - that's it. Game over. No more Twitter. All those connections lost in the wind.

If Google decided to shut down Gmail, it would be a blow - but email would continue working.

We need to be using protocols - not services. The reason email, http, ftp, can't be switched off is that anyone can use them for any purpose. They are not at the whim of any owner.

This is the future.

  • A LAMP stack running...
  • ...Federated Services...
  • ...based on open standards which can...
  • ...communicate over mesh networks...
  • ...protected and authenticated by strong cryptography
  • All running on hackable hardware.

Most of those requirements can run happily on an Android phone right now.

I'm enjoying playing with my Raspberry Pi - but I also have an eye on these "Android on a stick" system. Thinking Thumb Drives. Ready and waiting to do our bidding....

The Python Pals Program A Problem

As mentioned earlier, I've been inspired by the Byte Brothers to create a mystery story which kids have to solve using their l33t h4x0r skillz in Python.

This is loosely based on The Byte Brothers Go to a Getaway, by Lois and Floyd McCoy.
Byte Brothers Go To A Getaway
My well-thumbed copy was printed in 1984. I'm not sure when I got it, but I remember being around 8 or 9 when I first started writing programs in BASIC. Sadly, BASIC is as outdated as the Lascaux Cave Paintings, so I've written this in more friendly Python.

My hope is that people will write a bunch of interesting mystery stories (using these characters or their own) release them as Creative Commons, then we can put out a book AND SAVE THE WORLD!

Ahem...

Without further ado, I present to you the first adventure of "The Python Pals"!
Creative Commons Licence
This work is licensed under a Creative Commons Attribution 2.0 UK: England & Wales License.

The Morse Code Mystery

The Beachcombers

The waves crashed angrily on the beach, and the rain seemed to come in from all directions. A sudden gust blew a thin drizzle straight down Poppy's collar.
"This weather is foul," she spat.
"Just five more minutes," yelled Penny.

Poppy collapsed herself until she was eye level with her friend Penny. Even though Penny was the shorter of the two, she was hunched down on the beach anxiously glancing at the shoreline.

"Penny, what are we doing here? It's cold, wet, and most importantly," she paused for dramatic effect, "We're going to miss the Food Network's 'Marzipan Marathon'!"
Her friend giggled - neither of them could stand those TV cookery channels - but they had agreed there was something oddly compelling about watching a man trying to eat his body weight in cake.
"There!" Yelled Penny, pointing a little way down the shoreline. "I told you that interesting stuff gets washed up here when there's a storm. Grab it!"

Penny was used to being bossed around by Poppy. Despite being the older of the two friends, she was always being treated like Poppy's younger sister - so she relished in the chance to bark orders at her.

Penny scooped up the large square of blue canvas a spun around. "Please can we go in now?" she whined, "It's cold and wet and..."

Before she could even finish her sentence, Poppy exclaimed "Look! Look at the cloth!"

They both stared at the raggedy square of canvas. It was peppered with strange white marks.

"Let's get home and work out what this is," said Poppy. With that, she snatched the cloth from Penny, and started sprinting away toward her parent's home.

"That just what I was about to say!" yelled Penny, as she slowly trudged up the beach.

Pi Power

"Will you be wanting some soup, girls?" asked Poppy's mum, Ada. She had gotten used to both of them storming in and expecting to be fed.
"No time Ada, thanks," said Penny breathlessly, "We've got to work out what this is."

"Hmmm, looks like old fashioned Morse Code to me," said Ada after a moment's cursory examination of the cloth. "Where on Earth did you find..."

"Can we get some soup and croutons, and maybe some cheese. Do we have any crisps?" yelled Poppy as the girls bolted upstairs.

They flipped on the Raspberry Pi. It had been a birthday present from Poppy's dad. One of the few things she had left to remember him by. Just as Linux was quickly booting up, there was an enormous crack of thunder which shook the whole house. The lights flickered, then went off.

A second later they were back on, but there was a strange burning smell.

"Oh no! Cried Penny, "The router!"

Where their Internet router had been was a smouldering lump of twisted plastic and metal.

Poppy said a word which, if her mother had overheard her would have meant an instant reduction in pocket money. "How will we find out what 'Morse Code' is if we can't get online?"

The girls sat, stunned. No Internet. No Facebook. More importantly, no Wikipedia!

They looked at their phones but, as always they didn't have any credit.

Poppy looked around the room forlornly. The little study had been Poppy's dad's work area before he... Well. Just before. As she scanned the shelves looking for something which might help - even an old fashioned dial-up modem would do.

Penny suddenly chirruped, "Pops, what's the 'Encyclopedia Britannica'?" Pointing to an imposing set of books on a shelf.
"No idea," sniffed Poppy despondently.
"Only, and I know it was your dad's, but 'encyclopedia' sounds a bit like 'Wikipedia' and I wondered..."
Ad Encyclopaedia-Britannica 05-1913
"Of course! Quick, which one of the books has 'M' printed on the side?" Poppy smiled. It was rare to see her smile these days, and Penny relished cheering her friend up.

They plucked the dusty volume from the shelf and opened it up more-or-less at random. Its musty smell filled the room and they began flicking through the yellowing pages.
"Where's the search function on this thing?" joked Penny.
"Möbius, Moomins, Mormon, Morse!"

There, laid out in the pages of the encyclopedia was a guide to Morse Code.

Intcode

The girls flipped on the Pi and waited for it to boot.

"The most important thing to consider when programming," said Poppy doing her very best imitation of Mr Cartwright their inexcusably dull IT teacher.
"...is planning!" said Penny, finishing her friend's sentence.

"We want a program which will let us type in each letter of Morse Code and then show us the English translation."

Penny grabbed the keyboard. She knew that she would be doing most of the typing while Poppy did most of the pointing out of her mistakes. Apparently, this was known as "pair programming" according to Mr Cartwright. She didn't think much of it.

"First," said Poppy, "Let's define a dictionary of English and Morse Code."

Penny's hands darted across the keyboard as her friend read the dots and dashes from the book.

  1. morse = {  '.-'  :'A', '-...':'B', '-.-.':'C', '-..' :'D', '.'   :'E',
  2.            '..-.':'F', '--.' :'G', '....':'H', '..'  :'I', '.---':'J'
  3.         }

You can program the rest of the dictionary yourself.

Poppy sighed, "Why on Earth have you bothered to line up all the letters?"
"It helps me think," said Penny defensively, "I like it neat. Besides, Python doesn't care how I space things like that."
"Fine! Let's do a quick test to see if it works," said Poppy.
"Right, I'll ask the user to type a single letter of Morse Code. Then it's really easy to look it up in the dictionary," said Penny.

  1. get_code = raw_input('Type a Morse Character ')
  2. print morse[get_code]

She ran the program. As expected it asked her to type in a code. She hit the sequence ".-" and hit enter.

She was rewarded with a glowing "A" on the screen.

"Good start," said Poppy. "But it's going to be a pain to type in every Morse character, then hit enter, then try to string the letters together."

Penny thought for a moment. She knew she could come up with something clever.

"How about we read in the string we type in, then break it up based on where the spaces are?" She said tentatively.
Poppy looked confused, "What do you mean, Pen?"

Penny ran Python directly so she could show what she was thinking

Python 2.7.3 (default, Aug  1 2012, 05:14:39) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 

At the prompt she typed

  1. >>> "This is a test".split()

"If I'm right, the .split() function will give us an list of all the word."

She gently thumbed the enter key.

['This', 'is', 'a', 'test']

"Yes!" Shouted both girls simultaneously.

"So now we will have each Morse Letter in a list, then we want to look it up in the dictionary."
"That's right. Luckily it's super simple to do something on every item in a list - look,"

Penny typed directly into Python again.

  1. >>> list_of_words = "This is a test".split()
  2. >>> for item in list_of_words:
  3. ... print item

But this time, when she hit enter, an error message popped up!

  File "", line 2
    print item
        ^
IndentationError: expected an indented block

This time it was Penny's turn to swear.

"Wipe that grin off your face! Yes, spacing and indentation are important in Python. But generally it's fine if I line up my code just how I like it."

She tried again. This time hitting the spacebar as hard as she thought it could stand.

  1. >>> list_of_words = "This is a test".split()
  2. >>> for item in list_of_words:
  3. ...    print item

This time, the result was a lot more satisfactory.

... 
This
is
a
test
>>> 

"Getting there," muttered Poppy under her breath. They swiftly changed the last few lines of their code to read:

  1. get_code = raw_input('Type in the Morse Code ')
  2.  
  3. code_list = get_code.split()
  4.  
  5. for item in code_list:
  6.    print morse[item]

"Ok," said Penny, "Let's see what this mysterious blue cloth says on it..."

...  ---  ...  -...  ---  .- -  ...  .-  -.  -.-  ---  -.  ..  ...  .-..  .-  -.  -..

They checked and double checked what they had typed in.

"Ready?" said Poppy.
"Let's do it!" said Penny as she hit the enter key.

Saving The Day

"Well done you two," said the Mayor. "Without your help, that sailor would have been stuck there a long time."

Penny and Poppy both grinned. It had all been such a rush, they'd gone from running their code, to screaming for Poppy's mum, to calling the coastguard, to seeing a shipwrecked sailor being rescued. They had been interviewed for TV and the clip had hundreds of YouTube likes.

There was even a Facebook page dedicated to thanking them!

The Mayor had decided that such fine upstanding citizens deserved a reward - and had invited them to a special event in the town hall.

"Who would have thought two girls would know Morse Code?" They Mayor said, "Did you learn that at school?"

Penny fixed him with a steely glare, "No. We taught ourselves."

The Mayor peered over his glasses, "But surely you had help from someone? An older brother perhaps?"

Poppy knew the look on Penny's face and answered before her friend lost her temper, "I think you'll find," she said sweetly, "that women don't need help from boys!"

Poppy felt Penny's hand slip in to hers. She started to chuckle as her hand was squeezed in firm but measured bursts.

-  ....  .-  -  ...  .--  ....  -.--  -.--  ---  ..-  .-  .-.  .  --  -.--  -...  .  ...  -  ..-.  .-.  ..  .  -.  -..

THE END

What Next

  • Write your own story - using these character or ones you've created.
  • Make the Python simple and readable - explain as you go.
  • If there's enough interest, I'll gather them all up, maybe on a central site.
  • Perhaps, if people like them, we can release a (free) ebook?
  • Oh, and feel free to criticise my storytelling abilities or coding deficiencies!

3G Internet on Raspberry Pi - Success!

This is a bit of a brain dump of how I got a 3G USB dongle working on the Raspberry Pi. Following on from getting the Raspberry Pi to send SMS.

That's The Power Of Love

The first thing to say is use a powered USB hub! I had lots of problems getting the modem working when it was plugged directly into the Pi. A 3G signal takes more power than the Pi's USB sockets can supply.

3G Raspberry Pi

In the above image, you can see that the Raspbery Pi is plugged into the mains - via a 1.8A plug.
The USB cable has two male ends. The black plug goes directly into the Pi for data. The red plug goes into the mains via a 1A plug (an Amazon Kindle adapter).

I used a USB Y Cable to supply power and data.

I also tried plugging both plugs into the Pi - that didn't work either. You need a separate powered hub.

Rather than use two plugs, I'm going to try to find a mains plug with two USB sockets. Each socket needs to supply at least 1A. Something like this looks like it should do the trick.

Or, you can use a cable like this.

Put one male USB plug into the PI and the other into a power supply. The dongle fits into the female USB socket.

P-p-p-p-pick Up A PPPD

In order to get our network connected, we need to install the ppp package.

sudo apt-get install ppp

If You Think I'm Sakis, And You Want My Body...

I tried using wvdial and numerous other ways to connect to 3G. None of them worked reliably. In the end, I turned to sakis - the All-In-One script for connecting 3G modem.

Sakis says it is:

"The easiest way to have your 3G/UMTS/GRPS connection up and running."

I can't argue with that!

Installation is very simple:

First, download the latest version. The Raspberry Pi runs on an ARM processor, so this is the version we download.

wget "http://www.sakis3g.org/versions/latest/armv4t/sakis3g.gz"

The script is compressed. Unzip it.

gunzip sakis3g.gz

Finally, we want to make the file executable so that we can run it.

chmod +x sakis3g

Running sakis is quite straightforward. It has a basic GUI which will work even if you're just using the command line.

sudo ./sakis3g --interactive

sakis3g interface

Sakis has a fairly comprehensive list of connection details - it should find yours automatically and present you with this screen.
sakis3g interface APN

If it doesn't know your connection settings (if you're on GiffGaff for example) you can manually enter them.

All being well, after a few seconds, you should see this screen.
sakis3g interface connected

You can now exit sakis. You will stay connected.

To check the details of your connection, run the following command:

sudo ./sakis3g connect info

You'll get back something like this:

K3565 connected to giffgaff (23410).
Connection Information
 
Interface: P-t-P (ppp0)
 
Connected since: 2012-07-13 07:36
Kilobytes received: 2
Kilobytes sent: 2

Network ID: 23410
Operator name: giffgaff
APN: giffgaff.com
 
Modem: K3565
Modem type: USB
Kernel driver: option
Device: /dev/ttyUSB0
 
IP Address: 10.136.6.52
Subnet Mask: 255.255.255.255
Peer IP Address: 10.64.64.64
Default route(s): 10.64.64.64

That's it! You can now access the Internet via your 3G modem.

Surfin' Safari

One last tip for you! There's no need to start your window manager to surf the web. There's a brilliant lo-fi web browser called Lynx.

You install it by typing:

sudo apt-get install lynx

You run it by typing:

lynx http://www.bbc.co.uk/news

(or whatever website you want to visit).
lynx on the Raspberry Pi

So, that should be everything you need to get the Raspberry Pi connected over a USB 3G dongle. Have fun!

Raspberry Pi, Python, and 3G Dongles - oh my!

This is a bit of a brain dump / diary of what I've discovered about using 3G dongles to send SMS using Python on the Raspberry Pi.

Here is how to use Python to send an SMS from the Raspberry Pi via a 3G USB dongle.

In order to talk to the dongle, we need to install pyserial

wget http://pypi.python.org/packages/source/p/pyserial/pyserial-2.6.tar.gz
gunzip pyserial-2.6.tar.gz 
tar -xvf pyserial-2.6.tar 
cd pyserial-2.6
sudo python setup.py install

Save this file as sms.py - make sure you change the phone number and message!

  1. # This is pyserial which is needed to communicate with the dongle
  2. import serial
  3.  
  4. # Set up the connection to the dongle
  5. dongle = serial.Serial(port="/dev/ttyUSB0",baudrate=115200,timeout=0,rtscts=0,xonxoff=0)
  6.  
  7. # This sends the command to the dongle
  8. def sendatcmd(cmd):
  9.     dongle.write('AT'+cmd+'\r')
  10.  
  11. # put the dongle into text mode
  12. sendatcmd('+CMGF=1')
  13.  
  14. # Set the telephone number we want to send to
  15. sendatcmd('+CMGS="+447700900123"')
  16.  
  17. # Set the message we want to send
  18. dongle.write('Sending from python')
  19.  
  20. # Pass the CTRL+Z character to let the dongle know we're done
  21. dongle.write(chr(26))
  22.  
  23. # Close the connection
  24. dongle.close()

Run the file by typing

python sms.py

An SMS should be sent!

SMSC

The SMSC is the the message centre through which an SMS is sent. This is how to discover the SMSC of your SIM

AT+CSCA?

Should generate this as the output.

+CSCA: "+447802002606",145

SMS Modes

To see which modes your mobile supports, you can use the "AT+CMGF=?" command.
You will get a response with the supported SMS formats
0: PDU mode, 1: Text mode

Putting It All Together

My previous program calculated the PDU which needed to be sent to the dongle.

This program asks the user for the destination phone number, message, and whether they want to send a flash SMS or regular SMS.
It gets the SMSC from the dongle, calculates the PDU values, then sends them to the dongle.

Then - hopefully! - an SMS will be sent :-)

The source is on GitHub.

  1. # This Python file uses the following encoding: utf-8
  2. """
  3. © 2012 Terence Eden
  4.  
  5. Adapted from http://rednaxela.net/pdu.php Version 1.5 r9aja
  6. Original JavaScript (c) BPS & co, 2003. Written by Swen-Peter Ekkebus, edited by Ing. Milan Chudik, fixes and functionality by Andrew Alexander.
  7. Original licence http://rednaxela.net/pdu.php "Feel free to use this code as you wish."
  8.  
  9. Python version © 2012 Terence Eden - released as MIT License
  10. ***
  11. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  12.  
  13. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  14.  
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  16. ***
  17.  
  18. Note - this is my first Python program - I am quite happy to be corrected on True Pythonic Style etc. :-)
  19. """
  20.  
  21. """
  22. This program allows the user to craft a PDU when sending an SMS.
  23. The user enters the destination number, the message, the class, and the SMSC.
  24. The program generates the commands needed to instruct a modem to deliver the SMS.
  25. """
  26.  
  27. # This is pyserial which is needed to communicate with the 3G USB Dongle http://pyserial.sourceforge.net/
  28. import serial
  29.  
  30.  
  31. # Array with the default 7 bit alphabet
  32. # @ = 0 = 0b00000000, a = 97 = 0b1100001, etc
  33. # Alignment is purely an attempt at readability
  34. SEVEN_BIT_ALPHABET_ARRAY = (
  35.     '@', '£', '$', '¥', 'è', 'é', 'ù', 'ì', 'ò', 'Ç', '\n', 'Ø', 'ø', '\r','Å', 'å',
  36.     '\u0394', '_', '\u03a6', '\u0393', '\u039b', '\u03a9', '\u03a0','\u03a8', '\u03a3', '\u0398', '\u039e',
  37.     '€', 'Æ', 'æ', 'ß', 'É', ' ', '!', '"', '#', '¤', '%', '&', '\'', '(', ')','*', '+', ',', '-', '.', '/',
  38.     '0', '1', '2', '3', '4', '5', '6', '7','8', '9',
  39.     ':', ';', '< ', '=', '>', '?', '¡',
  40.     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
  41.     'Ä', 'Ö',
  42.                                                                      'Ñ', 'Ü', '§', '¿',
  43.     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
  44.     'ä', 'ö',
  45.                                                                      'ñ', 'ü',
  46.     'à')
  47.  
  48.  
  49. def semi_octet_to_string(input) :
  50.     """ Takes an octet and returns a string
  51. """
  52.     out = ""
  53.     i=0
  54.     for i in range(0,len(input),2) : # from 0 - length, incrementing by 2
  55.         out = out + input[i+1:i+2] + input[i:i+1]
  56.     return out
  57.  
  58.  
  59. def convert_character_to_seven_bit(character) :
  60.     """ Takes a single character.
  61. Looks it up in the SEVEN_BIT_ALPHABET_ARRAY.
  62. Returns the position in the array.
  63. """
  64.     for i in range(0,len(SEVEN_BIT_ALPHABET_ARRAY)) :
  65.         if SEVEN_BIT_ALPHABET_ARRAY[i] == character:
  66.             return i
  67.     return 36 # If the character cannot be found, return a ¤ to indicate the missing character
  68.  
  69.  
  70. def send_AT_command(cmd) :
  71.     """ Send a command to the dongle
  72. """
  73.     dongle.write(AT_COMMAND+cmd+'\r')
  74.    
  75.    
  76. def get_SMSC_from_dongle() :
  77.     """ Interogate the dongle and get the SMSC number
  78. """
  79.    
  80.     print "Asking the SIM for the SMSC"
  81.     # find the SMSC
  82.     send_AT_command('+CSCA?')
  83.  
  84.     # read the output, print it to screen. Stop when "OK" is seen
  85.     while True:
  86.         output = dongle.readline()
  87.         print output
  88.    
  89.         # find the response about the SMSC
  90.         if output.startswith("+CSCA:") :
  91.             first_quote = output.find('"') + 1 # zero based index, first quote
  92.             last_quote = output.rfind('"') # last quote
  93.             SMSC_number = output[first_quote:last_quote] # Extract the string between the "
  94.             print "The SMSC number is " + SMSC_number
  95.             return SMSC_number
  96.  
  97.         if output.startswith("OK"):
  98.             break
  99.         if output.startswith("ERROR"):
  100.             break
  101.  
  102.  
  103.  
  104. # Set the initial variables
  105. FIRST_OCTET = "0100" # MAGIC
  106. PROTO_ID = "00" # MORE MAGIC
  107. data_encoding = "1" # EVEN MORE MAGIC
  108. message_class = "" # Message Class. 0 for FLASH, 1 for normal
  109. SMSC_number = "" # The message centre through which the SMS is sent
  110. SMSC = "" # How the SMSC is represented once encoded
  111. SMSC_info_length = 0
  112. SMSC_length = 0
  113. SMSC_number_format = "81" # by default, assume that it's in national format - e.g. 077...
  114. destination_phone_number = "" # Where the SMS is being sent
  115. destination_phone_number_format = "81" # by default, assume that it's in national format - e.g. 077...
  116. message_text = "" # The message to be sent
  117. encoded_message_binary_string = "" # The message, as encoded into binary
  118. encoded_message_octet = "" # individual octets of the message
  119. AT_COMMAND = "AT" # Commands sent to dongle should start with this
  120. AT_SET_PDU = "+CMGF=0" # Command to set the dongle into PDU mode
  121. SEND_CHARACTER = chr(26)
  122.  
  123. # Set up the connection to the dongle
  124. dongle = serial.Serial(port="/dev/ttyUSB0",baudrate=115200,timeout=0,rtscts=0,xonxoff=0)
  125.  
  126. # Get the user inputs. No error checking in this version :-)
  127. get_destination_phone_number = raw_input("Which phone number do you want to send an SMS to? (e.g. +447700900123) : ")
  128. get_message_text = raw_input("What message do you want to send? : ")
  129. get_message_class = raw_input("For FLASH SMS, type 0. For regular SMS, type 1 : ")
  130.  
  131. # TODO Error check & sanitize input
  132. destination_phone_number = get_destination_phone_number
  133. message_text = get_message_text
  134. message_class = int(get_message_class)
  135. SMSC_number = get_SMSC_from_dongle() #get_SMSC_number
  136.  
  137. # Set data encoding
  138. data_encoding = data_encoding + str(message_class)
  139.  
  140. # Get the SMSC number format
  141. if SMSC_number[:1] == '+' : # if the SMSC starts with a + then it is an international number
  142.     SMSC_number_format = "91"; # international
  143.     SMSC_number = SMSC_number[1:len(SMSC_number)] # Strip off the +
  144.  
  145. # Odd numbers need to be padded with an "F"
  146. if len(SMSC_number)%2 != 0 :
  147.     SMSC_number = SMSC_number + "F"
  148.  
  149. # Encode the SMSC number
  150. SMSC = semi_octet_to_string(SMSC_number)
  151.  
  152. # Calculate the SMSC values
  153. SMSC_info_length = (len(SMSC_number_format + "" + SMSC))/2
  154. SMSC_length = SMSC_info_length;
  155.  
  156. # Is the number we're sending to in international format?
  157. if destination_phone_number[:1] == '+' : # if it starts with a + then it is an international number
  158.     destination_phone_number_format = "91"; # international
  159.     destination_phone_number = destination_phone_number[1:len(destination_phone_number)] # Strip off the +
  160.  
  161. # Calculate the destination values in hex (so remove 0x, make upper case, pad with zeros if needed)
  162. destination_phone_number_length = hex(len(destination_phone_number))[2:3].upper().zfill(2)
  163.  
  164. if len(destination_phone_number)%2 != 0 : # Odd numbers need to be padded
  165.     destination_phone_number = destination_phone_number + "F"
  166.  
  167. destination = semi_octet_to_string(destination_phone_number)
  168.  
  169. # Size of the message to be delivered in hex (so remove 0x, make upper case, pad with zeros if needed)
  170. message_data_size = str(hex(len(message_text)))[2:len(message_text)].upper().zfill(2)
  171.  
  172. # Go through the message text, encoding each character
  173. for i in range(0,len(message_text)) :
  174.     character = message_text[i:i+1] # get the current character
  175.     current = bin(convert_character_to_seven_bit(character)) # translate into the 7bit alphabet
  176.     character_string = str(current) # Make a string of the binary number. eg "0b1110100
  177.     character_binary_string = character_string[2:len(str(character_string))] # Strip off the 0b
  178.     character_padded_7_bit = character_binary_string.zfill(7) # all text must contain 7 bits
  179.     # Concatenate the bits
  180.     # Note, they are added to the START of the string
  181.     encoded_message_binary_string = character_padded_7_bit + encoded_message_binary_string
  182.  
  183.  
  184. # Reverse the string to make it easier to count
  185. encoded_message_binary_string_reversed = encoded_message_binary_string[::-1]
  186.  
  187. # Get each octet into hex
  188. for i in range(0,len(encoded_message_binary_string_reversed),8) : # from 0 - length, incrementing by 8
  189.     # Get the 8 bits, reverse them back to normal, if less than 8, pad them with 0
  190.     encoded_octet = encoded_message_binary_string_reversed[i:i+8][::-1].zfill(8)
  191.     encoded_octet_hex = hex(int(encoded_octet,2)) # Convert to hex
  192.    
  193.     # Strip the 0x at the start, make uppercase, pad with a leading 0 if needed
  194.     encoded_octet_hex_string = str(encoded_octet_hex)[2:len(encoded_octet_hex)].upper().zfill(2)
  195.    
  196.     # Concatenate the octet to the message
  197.     encoded_message_octet = encoded_message_octet + encoded_octet_hex_string
  198.  
  199. # Generate the PDU
  200. PDU = str(SMSC_info_length).zfill(2) \
  201.         + str(SMSC_number_format) \
  202.         + SMSC \
  203.         + FIRST_OCTET \
  204.         + str(destination_phone_number_length) \
  205.         + destination_phone_number_format \
  206.         + destination \
  207.         + PROTO_ID \
  208.         + data_encoding \
  209.         + str(message_data_size) \
  210.         + encoded_message_octet
  211.  
  212. # Generate the AT Commands
  213. AT_CMGS = "+CMGS=" + str((len(PDU)/2) - SMSC_length - 1)
  214.  
  215. # Show the commands
  216. print AT_COMMAND + AT_SET_PDU
  217. print AT_COMMAND + AT_CMGS
  218. print PDU
  219.  
  220. # Send the commands to the dongle
  221. send_AT_command("") # Send an initial AT
  222. send_AT_command(AT_SET_PDU) # Send the command to place the dongle in PDU mode
  223. send_AT_command(AT_CMGS) # Send the command showing the length of the upcoming PDU, should prompt for input ">"
  224. dongle.write(PDU) # Send the PDU
  225. dongle.write(SEND_CHARACTER) # Submit the PDU
  226. dongle.close() # Close the connection

The source is on GitHub.