Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Saturday, February 7, 2015

The Zen of Python


The Zen of Python, by Tim Peters, is guiding principles for Python's design.

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

This list can also be generated within python by executing:
>>> import this







Sunday, November 9, 2014

Twitter Logger with Python


Want a more modern method for simple logging and notifications? Twitter is very popular, but it normally too "noisy" for me to follow for social messages. Add a bit of tech and now I have a reason to check Twitter at least once a day, or follow the events on my phone.

I had read articles in both Linux Journal and The MagPi Magazine about engineering minds using Twitter to receive notifications when certain events occur. I decided to take this a step further and create a tiny Twitter logger script for all of my Raspberry Pis. I now receive notifications for all kinds of events, such as:

  • Daily "alive" notifications
  • Reboots, power cycles
  • Changes in dynamic IP address
  • GPIO event triggers (think security alarm, garage door, sprinkler system, etc)
  • And anything else that fancies me at the moment

Code

How complicated is the Python? Easy. Only 3 lines (ignoring the line wrapping and commented debug code):
import twitter

api = twitter.Api(consumer_key='XXX',
                  consumer_secret='XXX',
                  access_token_key='XXX',
                  access_token_secret='XXX')

status = api.PostUpdate('This is my status update')

# print status.text

To use this code you will need to first generate your Twitter App API Access Keys and also install the python-twitter Python package.

Twitter App API Access Keys

Step 1 - Twitter Account: So how does one get started?  Well first, you need a Twitter account.  I assume you already have one, or at least don't need help creating one.

Step 2 - Mobile Phone: Unfortunately, your code will only be able to read status updates, unless you tie a mobile phone number to your account. Once you have validated your mobile phone, you will then be able to write/post status updates as well. Go to your account Settings and select the Mobile section. Add your mobile phone number, and wait for the validation code to appear on your phone. (note: I did attempt to try a couple of free burner mobile phone numbers, none of which ever received the validation code)

"You must add your mobile phone to your Twitter profile before granting your application write capabilities. Please read https://support.twitter.com/articles/110250-adding-your-mobile-number-to-your-account-via-web for more information"
Step 3 - Twitter App: Next, we need to create a Twitter App. This is nothing more than a method to get access to your api keys. Browse to https://apps.twitter.com/ and click the "Create New App" button.

Fill in the Name, Description and Website fields, then accept the agreement and continue.

The important field is the Name field as it has to be unique among all Twitter Apps. I just used my twitter account name, as I assumed no one else would be using that for an app name.

The Website field has to be populated, but won't be used. Put some temporary website and continue.

The Callback URL can be ignored.


Step 4 - Access Level: After the Twitter App has been created, find the Application Settings section and modify the Access level option by clicking the Modify App Permission link.  Change the access level from Read Only to Read and Write.  If you receive a warning about your mobile phone number, go back to step 2.

Step 5 - Access Keys: Finally, find the Application Settings section again and click the Manage Keys and Access Tokens link. You will find the consumer keys at the top of the page. Under the Your Access Token section, click the Create My Access Token button to generate the access tokens. If it isn't obvious the keys match the code variables as such:
consumer_key = "Consumer Key (API Key)"
consumer_secret = "Consumer Secret (API Secret)"
access_token_key = "Access Token"
access_token_secret = "Access Token Secret"

Now with your access keys, you can begin using the code above to update your twitter status with various notifications.

python-twitter

The python-twitter package "provides a pure Python interface for the Twitter API." To install the python-twitter package, simply use pip.
$ sudo pip install python-twitter

That was easy.

Check Status Code

The previous code showed how we can post a new update, but what about getting our current status, or someone else's?
import twitter
api = twitter.Api(...)

# get my timeline
statuses = api.GetUserTimeline()

# get a specific user's timeline:
# statuses = api.GetUserTimeline(screen_name=SCREEN_NAME)

# show latest message only:
print statuses[0].text

# show all returned messages:
for s in statuses:
       print s.text

Catch Errors

There are a few important errors that you will probably run across, and should handle:

Authentication failure: (check your keys, especially for accientally copied space characters)
twitter.error.TwitterError: [{u'message': u'Could not authenticate you', u'code': 32}]

Too long of a message: (shorten your message)
twitter.error.TwitterError: [{u'message': u'Status is over 140 characters.', u'code': 186}]

Duplicate message: (don't repeat messages or add a unique id, like time)
twitter.error.TwitterError: [{u'message': u'Status is a duplicate.', u'code': 187}]

User does not exist: (check the user name you are trying to query)
twitter.error.TwitterError: [{u'message': u'Sorry, that page does not exist', u'code': 34}]
test

Cronjob

I updated the twitter script to accept a message from the command line, and then added it to my cronjob:
@daily      /usr/bin/python /usr/local/bin/twitter alive
@reboot     /usr/bin/python /usr/local/bin/twitter reboot

Tips

#1 To be able to group and sort messages, I would recommend using the power of the hashtag. Pick a unique identifier (maybe your username) and append a category like this:
system startup #oeey_garage_pi

#2 To avoid the "Status is a duplicate" you may also wish to append a unique ID to all messages. I like to use the current linux epoc time, like this:
system startup #oeey_garage_pi (1415571010)

The updated posting code would look like this:
import time
...
status = api.PostUpdate('{message} #{category} ({id})'.format(
        message=message,
        category=category,
        id=int(time.time())

Issues


InsecurePlatformWarning:
/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning. InsecurePlatformWarning
Solution: either ignore the warning or upgrade to at least Python 2.7.9 (or change code to use pyOpenSSL).

Other Libraries

If Python is not your thing, there a number of other Twitter libraries for various other programming platforms.

That's All Folks


Good luck, and have a good time playing with Python and Twitter.







Friday, October 3, 2014

Introduction to the Google Calendar API (HOWTO)




I have used Google Calendars to schedule and control a number of projects (eg. sprinkler system, alarm clock, etc) .  The following How To will get you started.  You will of course need a google account.


Create Project


1) Start by visiting the Google Developers Console

and create a new project.


2) Select the project and navigate on the left menu to APIs & auth then APIs and enable Calendar API for this project.  You can disabled all other APIs if you only need Calendar access.


3) Next, select the Consent screen menu option from the APIs & auth menu.  Enter a Product Name and select an Email Address.  If you do not do this step, you will get a Error: invalid_client error later on.


4) Next, select the Credentials menu option from the APIs & auth menu.  Under OAuth select Create new Client ID.


5) For the Create Client ID select Installed application for Application Type and select Other for Installed Application Type and finally click the Create Client ID button.


6) After the ID has finished being created, click the Download JSON button.  Save and rename the file as something simple like client_secret.json.

This json file contains your API credentials needed to access the Google Calendar APIs.


Install Google API Libraries


1) Install the Google API Libraries using Python's PIP installer:
$ sudo pip install --upgrade google-api-python-client

gflags may or may not be needed, depending on what code you use: (may be optional)
$ sudo pip install --upgrade python-gflags

If you would prefer alternatives, view the Google APIs Client Library for Python page.

Authorize Application


Next we will need to run our application and authorize it against the desired account.

1) Clone my sample code:
# git clone https://github.com/oeey/gcalendar.git

The sample code is just a slight modification from the Getting Started Sample Code.  The Google sample code has some outdated code that will throw some obsoleted warnings.

2) The application has not been authorized to an account yet.  Run the application once and you will be asked to paste a validation URL into your browser.  Login to your desired target account (with the calendars you want to access) and then paste the validation URL into your browser.

For convenience I have a first_auth.py script that is the same script as the gcalendar.py script, but terminates after authorization.  You can run any of the scripts to complete this authorization step.

The first_auth.py is pretty simple:
from apiclient.discovery import build
from oauth2client.file import Storage
from oauth2client.client import AccessTokenRefreshError
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run_flow
from oauth2client.client import flow_from_clientsecrets

def main():
    scope = 'https://www.googleapis.com/auth/calendar'
    flow = flow_from_clientsecrets('client_secret.json', scope=scope)

    storage = Storage('credentials.dat')
    credentials = storage.get()

    class fakeargparse(object):  # fake argparse.Namespace
        noauth_local_webserver = True
        logging_level = "ERROR"
    flags = fakeargparse()

    if credentials is None or credentials.invalid:
        credentials = run_flow(flow, storage, flags)

if __name__ == '__main__':
    main()

You may notice the "fakeargparse" code. The run_flow() call wants the flags to be set from the parameters pulled from argparse. I think that is overkill for what I needed, so I just created a fake container so run_flow() wouldn't complain.

Run the first_auth.py script to collect the application authorization.
$ python first_auth.py
Go to the following link in your browser:

    https://accounts.google.com/o/oauth2/auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code&client_id=1039XXXXXXXXXXXXXXXXXXXXXXXXXXcs46gdj2.apps.googleusercontent.com&access_type=offline

Enter verification code:

3) Copy the URL into the browser and accept the permissions.


4) You will be presented with a code, to which you will then enter back into the prompt of the first_auth.py application.  The authorization will be stored in the credentials.dat file for future requests.
$ python first_auth.py
Go to the following link in your browser:

    https://accounts.google.com/o/oauth2/auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code&client_id=46XXXXXXXXXX2-bXXXXXXXXXXXXXusvh6.apps.googleusercontent.com&access_type=offline

Enter verification code: 4/WzAQfXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2vw2M2Pl7OykQI
Authentication successful.

Now that we have our API credentials and are authorized to access an account, we can begin to play with the Google Calendars.


View Upcoming Events


The upcoming.py script builds off of the first_auth.py script, cycles through the next few upcoming calendar events and displays the event titles.
...
    if credentials is None or credentials.invalid:
        credentials = run_flow(flow, storage, flags)

    http = httplib2.Http()
    http = credentials.authorize(http)
    service = build('calendar', 'v3', http=http)

    print "Upcoming Events:"
    request = service.events().list(calendarId='primary')
    while request != None:
        response = request.execute()
        for event in response.get('items', []):
            print event.get('summary', 'NO SUMMARY')
        request = service.events().list_next(request, response)

This script defaults to the primary calendar associated with the account.


Calendar ID


The previous script defaults to the primary calendar associated with the account.  If you wish to specify an alternate calendar, you will need the Calendar ID.  A calendar's ID can be found on the Calendar Details setting page (same page you can change a calendar's name on).  Look for the Calendar Address line, and the Calendar ID will be in the parenthesis.  It will look something like "a3sd5221ap2qe5ksbev3ip4@group.calendar.google.com".


Next 12 Hours of Events


Finally, to specify a time range for events, I use the following code in my gcalendar.py script.  This code will collect the next 12 hours worth of events.
  ...

    service = build('calendar', 'v3', http=http)

    # get the next 12 hours of events
    epoch_time = time.time()
    start_time = epoch_time - 3600  # 1 hour ago
    end_time = epoch_time + 12 * 3600  # 12 hours in the future
    tz_offset = - time.altzone / 3600
    if tz_offset < 0:
        tz_offset_str = "-%02d00" % abs(tz_offset)
    else:
        tz_offset_str = "+%02d00" % abs(tz_offset)
    start_time = datetime.datetime.fromtimestamp(start_time).strftime("%Y-%m-%dT%H:%M:%S") + tz_offset_str
    end_time = datetime.datetime.fromtimestamp(end_time).strftime("%Y-%m-%dT%H:%M:%S") + tz_offset_str

    print "Getting calendar events between: " + start_time + " and " + end_time

    events = service.events().list(calendarId='primary', timeMin=start_time, timeMax=end_time, singleEvents=True).execute()singleEvents=True).execute()
    #pprint.pprint(events)
    for event in events['items']:
        print event["summary]


And this is the basis for the code I use to schedule my sprinkler system with.





Sunday, December 22, 2013

TEMPer USB Thermometer on Raspberry Pi

TEMPer USB Thermometer
For a fairly cheap solution, nothing quite compares in price and convenience to the TEMPer USB Thermometer.  Due to their low price point, I have used several of these as secondary temperature check points in a server rack before.  They can be picked up for about $15 to $22 on Amazon, or cheaper on eBay.  The TEMPer is not as accurate, or reliable, as something like the Temperature@lert, which runs for about $130, but for general temperature estimation they work sufficient for my needs.

I found the easiest way to use the TEMPer with Python is to install the pyusb library and a simple temper Python class written by Bill Mania.  There were a few small issues that I ran into with the original code, so I forked the code on Github and posted the changes as the PyTEMPer repo seen below.

First let's make sure Linux can see your TEMPer device. We are looking for devices that have the VendorID of 1130 and DeviceID of 660c.
# lsusb | grep 1130:660c
Bus 004 Device 002: ID 1130:660c Tenx Technology, Inc. Foot Pedal/Thermometer

If your device is not found, the PyTEMPer script will not work with your device.

PyTEMPer Installation:
# cd /opt

# ## forked from http://www.manialabs.us/downloads/Temper.py
# sudo git clone https://github.com/kiloforce/PyTEMPer
# cd PyTEMPer

# ## Get PyUSB (if you do not already have installed)
# sudo git clone https://github.com/walac/pyusb
# sudo ln -s pyusb/usb usb

# ## Get sample temperature to verify code is setup correctly
# sudo python temper.py
0:2, 22.56 Celsius / 72.61 Fahrenheit

Now that we have the PyTEMPer class working, we can build the following Python script to get the current temperature repeatedly:
import sys
import time

sys.path.append('/opt/PyTEMPer')
import temper
temp = temper.Temper()

if not temp.devices:
    print "Error: not TEMPer devices found!"
    sys.exit(1)
device = temp.devices[0]

while True:
    # get temperature
    tempc = temp.getTemperature(device)
    print "Celsius: " + str(tempc)

    # only check temperatures every 10 seconds
    time.sleep(10)

In the final lala-pi TEMPer code, I included code to demonize the process, syslog for logging, and ZeroMQ messaging.  If you are interested in the full lala-pi source code (still a work in progress), this can be found in the GitHub lala-pi repo on Bitbucket.
# git clone https://github.com/oeey/lala-pi

More to come...   see label: lala-pi

USB Keyboard on Raspberry Pi

Targus Numeric Keypad

For the lala-pi "room security system" project I am building, I needed a way for an intruder to enter in a security code to disable the security system.  A full keyboard is a bit too bulky.  Luckily, small USB numeric "Ten Key" keypads are common, and fairly cheap.  I am sure their primary market is for accountants, but I purchased one to accompany my small laptop keyboard, some years ago.

Targus keypad model

I connected the keypad to the Raspberry Pi, and immediately noticed the first roadblock.  The keypad sends key presses to the system console, not to the SSH session I use to manage the Pi.  As this Pi will be headless, I needed to find a way to capture input from the keypad.

Fortunately for me, there is already a Python project called "evdev" that:
"provides bindings to the generic input event interface in Linux. The evdev interface serves the purpose of passing events generated in the kernel directly to userspace through character devices that are typically located in /dev/input/"
Score!

This solution would work equally well with a keypad or a full-sized keyboard.  The only difficult problem was determining which /dev/input/ device to use.  This particular keypad appeared as "/dev/input/by-id/usb-ORTEK_USB_Keyboard_Hub-event-kbd".  Your's may appear differently.

Here is the first bit of code I used to test the keypad, which worked quite well:
#!/usr/bin/env python

import string
import os
import sys
import time

# pip install evdev
from evdev import InputDevice
from select import select

# look for a /dev/input/by-id/usb...kbd or something similar
DEVICE = "/dev/input/by-id/usb-ORTEK_USB_Keyboard_Hub-event-kbd"

dev = InputDevice(DEVICE)

while True:

    # wait for keypad command
    r, w, x = select([dev], [], [])

    # read keypad        
    for event in dev.read():
        if event.type==1 and event.value==1:
            if event.code in keys:
                print "KEY CODE: " + event.code
                # do something with this key press
                # ...

In the final lala-pi keypad code, I included code to demonize the process, key-code to key-name mappings, syslog for logging, and ZeroMQ messaging.  If you are interested in the full lala-pi source code (still a work in progress), I setup a GitHub lala-pi repo.
# git clone https://github.com/oeey/lala-pi.git

For reference, this is the keycode to key name mapping I use:
# keymapping determined by trial and error
keys = {
 79: "1",
 80: "2",
 81: "3",
 75: "4",
 76: "5",
 77: "6",
 71: "7",
 72: "8",
 73: "9",
 82: "0",
 83: ".",
 28: "ENTER",
 78: "+",
 74: "-",
 14: "BS",
 55: "*",
 98: "/",
 # Numlock keys:
 111: "N.",
 110: "N0",
 107: "N1",
 108: "N2",
 109: "N3",
 105: "N4",
 # notice the missing N5
 106: "N6",
 102: "N7",
 103: "N8",
 104: "N9",
}

More to come...   see label: lala-pi

Saturday, December 21, 2013

ZMQ Messaging System - lala-pi

ZeroMQ Messaging Service
The first hurdle I ran into with this over-engineered room security system, was the complexity of the monolithic application, I was putting together, to control the various sensors and devices.  Luckily, a coworker suggested I break the system up into smaller components and use a messaging system.  This is a common practice for enterprise level applications.

Message-oriented middleware (MOM)

For reference: "Message-oriented middleware (MOM) is software or hardware infrastructure supporting sending and receiving messages between distributed systems. MOM allows application modules to be distributed over heterogeneous platforms and reduces the complexity of developing applications that span multiple operating systems and network protocols. The middleware creates a distributed communications layer that insulates the application developer from the details of the various operating systems and network interfaces." (ref)

That is a fancy way of saying that instead of a monolithic application, smaller self contained applications send messages and requests between each other.  This allows individual components to be maintained individually, and also allows one to potentially duplicate components for distributed load balancing.

Would my little security system become more complex, or simplified by adding a messaging system?  I determined that the education alone would be worth it, so I jumped onto the messaging system bandwagon.

Messaging System Options

I researched several messaging system options, with my primary requirements being:

  • Compatibility with the Raspberry Pi
  • Compatibility with Python
  • Low memory footprint
  • Fast performance
After investigating popular options such as ActiveMQ and RabbitMQ, I settled on a tiny messaging system called ZeroMQ.

ZeroMQ

ZeroMQ (also ØMQ or ZMQ) is a minimal Message-oriented middleware (MOM).  It is only a small step above just using bare TCP sockets, but provides enough messaging power to do pretty much anything you could want.

The first benefit of ZeroMQ is it takes the TCP socket stream and breaks it down into the individual messages for me.  I then don't have to worry if the partial data stream I receive is complete or not.  With ZeroMQ you receive the whole message, or not.  Messages are all "string" based, which makes them easy for Programming languages like Python to handle.  If you need to send non-string messages, you will need to decode them from the received string, or play with the optional RAW messaging functions.

The second benefit of ZeroMQ is it handles connections for me.  I don't have to worry about if a connection is lost, as it will reconnect for me, when able to.  I also don't have to worry about if a server doesn't exist at the time a client connects, as ZeroMQ will auto connect to the server when the server eventually comes online.

The third benefit of ZeroMQ is it handles distributed messages out of the box.  I can send a single message to my publishing pipe, and any clients that are subscribed to that pipe will receive the message.

ZMQ Patterns

According to the ZeroMQ documentation, the following messaging patterns are baked into it's core:
  • Request-reply, which connects a set of clients to a set of services. This is a remote procedure call and task distribution pattern.
  • Pub-sub, which connects a set of publishers to a set of subscribers. This is a data distribution pattern.
  • Pipeline, which connects nodes in a fan-out/fan-in pattern that can have multiple steps and loops. This is a parallel task distribution and collection pattern.
  • Exclusive pair, which connects two sockets exclusively. This is a pattern for connecting two threads in a process, not to be confused with "normal" pairs of sockets.
The pattern I have chosen to use for my room security system is the Publisher-Subscriber model, with a message router in the middle that will replay all messages to every other application in the system.  Applications can then choose which messages to subscribe to (or even all of them), and which to ignore.

For example, my keypad application will be waiting for a key press.  When a key is pressed, such as the "LEFT" key, it will generate a "KEY: LEFT" message and send it to the message router.  The message router will then turn around and replay the "KEY: LEFT" to any application that is subscribed to messages prefixed with "KEY:".  The music player application, which is listening for "KEY:" will then pick up the message and take the predetermined action, such as going to the previous song.

Another fascinating side effect from this setup is I could generate a "KEY: LEFT" message from any application, such as a web interface, or even a cell phone app.  Security issues aside, think of the possibilities.  I know, this blew my mind too!

Installation

There are two parts to get ZeroMQ installed and working with Python.  First, you need the system libraries, and second the Python bindings.

System Libraries:
# For Raspbian:
apt-get install python-zmq

Python Binding:
easy_install pyzmq
# or
pip install pyzmq

Source Code

If you are interested in the full code (still a work in progress), see the lala-pi repo on GitHub.
# git clone https://github.com/oeey/lala-pi.git

Message Router

As ZeroMQ is a minimal messaging system, you are left on your own to build the messaging router services.  Thankfully this is quite simple.

Here is the minimal message router I started with:
#!/usr/bin/env python

import os
import sys
import time

import zmq

# ZMQ context, only need one per application
context = zmq.Context()

# for sending messages
z_send = context.socket(zmq.PUB)
z_send.bind("tcp://*:5555")

# for receiving messages
z_recv = context.socket(zmq.SUB)
z_recv.bind("tcp://*:5556")
z_recv.setsockopt(zmq.SUBSCRIBE, '')  # subscribe to everything

print "ZMQ server started."
while True:
    message = None

    # wait for incoming message
    try:
        message = z_recv.recv()
    except zmq.ZMQError as err:
        print "Receive error: " + str(err)

    # replay message to all subscribers
    if message:
        try:
            z_send.send(message)
        except zmq.ZMQError as err:
            print "Send error: " + str(err)

I then added some logging of the messages, and a bit of clean up code for a more robust message router:
#!/usr/bin/env python

import os
import sys
import time

import zmq

# ZMQ context, only need one per application
context = zmq.Context()

# for sending messages
z_send = context.socket(zmq.PUB)
z_send.bind("tcp://*:5555")

# for receiving messages
z_recv = context.socket(zmq.SUB)
z_recv.bind("tcp://*:5556")
z_recv.setsockopt(zmq.SUBSCRIBE, '')  # subscribe to everything

# record all message requests to a file
record = open('router-records.txt', 'w')

# counters for messages
last_time = time.time()
count = 0

print "ZMQ server started."
while True:
    message = None

    # wait for incoming message
    try:
        message = z_recv.recv()
    except zmq.ZMQError as err:
        print "Receive error: " + str(err)

    # if message received, and not an error, then
    # replay message to subscribers
    if message:
        count += 1
        record.write(str(count) + ':' + message + '\n')
        
        # occasionally flush the router-record.txt file
        if time.time() > last_time + 2:
            record.flush()
            last_time = time.time()

        try:
            z_send.send(message)
        except zmq.ZMQError as err:
            print "Send error: " + str(err)

        if message.strip() == "DEATH":
            print "Death received, shutting down."
            break


print "Shutting down..."
record.close()
z_send.close()
z_recv.close()
context.term()
print "Shut down."

My final version also includes some "forking" code to daemonize (background) the application. As print statements would be lost to the void, I also converted all of the print statements over to using syslog.  The full source can be found in the Bitbucket repo.

Now, with a working router, I can build any application, connect to the message router and have a fully functional messaging system.

Message Client

For a sample messaging client, here is my "test" client that I use. Using this as a template, a full application could be constructed
#!/usr/bin/env python

import os
import sys
import time

import zmq

context = zmq.Context()

z_recv = context.socket(zmq.SUB)
z_recv.connect("tcp://localhost:5555")

z_send = context.socket(zmq.PUB)
z_send.connect("tcp://localhost:5556")
# z_recv.setsockopt(zmq.SUBSCRIBE, 'KEYBOARD:')
z_recv.setsockopt(zmq.SUBSCRIBE, '')  # subscribe to everything

print "ZMQ Client Started!"

while True:
    sys.stdout.write("Message: ")
    message = raw_input().strip()

    if message:
        try:
            print 'SEND:' + message
            z_send.send(message)
        except zmq.ZMQError as err:
            print 'Send error: ' + str(err)

    try:
        # don't block if no message waiting
        in_message = z_recv.recv(zmq.DONTWAIT)
        print 'RECV:' + in_message
    except zmq.ZMQError as err:
        print 'Receive error: ' + str(err)


More to come...   see label: lala-pi