You are on page 1of 71

Evaluation of the Zero MQ Socket Library by Alan Matthews

This report is submitted in partial fulfilment of the requirements of the B.Sc. Honours Degree in Networking Applications & Services, of the Dublin Institute of Technology

March 15th, 2014 Supervisor: Mr Frank Duignan School of Electrical and Electronic Engineering

Evaluation of the Zero MQ socket library

DT080B

Acknowledgements
I would just like to take this opportunity to thank Ms Paula Kelly for her suggestions and input on messaging oriented middleware, and Ms Brid Mcloughlin for her proof reading and editorial services and most of all Mr Frank Duignan, for his time, effort and patience in guiding and motivating me towards the completion of the project. His help and expertise, were invaluable, and his contribution to the project was far beyond what was required or expected of him.

Declaration
This final year project is presented in partial fulfilment of the requirements for a the B.Sc. Honours Degree in Networking Applications & Services It is entirely my own work and has not been submitted to any other university or higher education institutio n, or for any other academic award in this University. The work was completed under the guidance of Mr Frank Duignan. Furthermore, I took reasonable care to ensure that the work is original, and, to the best of my knowledge, does not breach copyright law, and has not been taken from other sources except where such work has been cited and acknowledged within the text. Signed _____________________________________________________ D.I.T Student Number _________________________________________ Date _______________________________________________________ Page 2 of 71

Evaluation of the Zero MQ socket library

DT080B

Table of Contents
Acknowledgements................................................................................................................ 2 Declaration............................................................................................................................. 2 Abstract .................................................................................................................................. 4 Chapter 1 Introduction ........................................................................................................... 5 Chapter 2 What is ZeroMQ ................................................................................................. 7 Chapter 3 ZeroMQ Sockets ................................................................................................... 9 Chapter 5 ZMQ Pattern Examples:...................................................................................... 19 Chapter 6 Implementation Motion sensor ........................................................................... 29 Chapter 7 Implementation Twitter....................................................................................... 32 Chapter 8 Implementation Analogue sensors ...................................................................... 34 Chapter 9 Implementation Adding the camera .................................................................... 39 Chapter 10 Implementation push button and outputs .......................................................... 42 Chapter 12 Implementation Outputs.................................................................................... 46 Chapter 13 Implementation Email ....................................................................................... 48 Chapter 14 Implementation Text Messaging....................................................................... 51 Chapter 15 Implementation Facebook ................................................................................. 54 Chapter 16 Discussion ......................................................................................................... 55 Conclusion ........................................................................................................................... 56 Bibliography ........................................................................................................................ 57 Appendices .......................................................................................................................... 58

Page 3 of 71

Evaluation of the Zero MQ socket library

DT080B

Abstract
The principle objective of this paper is to investigate the Zmq messaging library. This was achieved using a Raspberry PI acting as a home monitoring system with several sensors. This system used the ZMQ messaging library, to send data to a server, which decides on appropriate action and sends messages back to the PI and alerts through social media and text. Some challenging aspects of this project were using analogue sensors with a digital system, deciding on which ZMQ pattern to use, and adding an image to the text updates. Each Module was built and tested separately before being integrated into the main system The system successfully demonstrates a basic ZMQ Pattern.

Page 4 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 1 Introduction
The initial plan for this project was for the Raspberry PI to act as a home monitoring system with several sensors including both analogue and digital sensors. This system would use the ZMQ messaging library to send data to a server, which would then decide on appropriate action and send alerts through social media and text. Several problems had to be addressed in this project including: Which ZeroMQ messaging pattern to use? How to integrate analogue sensors into a digital system? How to decide and take action for each condition? How to integrate social media updating into the system? How to send a text message from a pi system? How to automatically send an update at a certain time? How to use a received message to activate an action?

It was decided to use a Request Reply ZeroMQ pattern as each input from the sensors would require action. For example, if it was dark the PI would be required to turn on a light. The system also would be required to send updates on a timed basis as to the status. In the sensor array, the sensors required were a digital motion sensor, a temperature sensor, a light sensor, and a push or panic button. The temperature and light sensors were analogue sensors and as the Raspberry PI has no analogue input, an analogue to digital converter would be required. An If-else conditional statement was used to monitor the status of the sensors and if one of the conditions was found to be true to send a message using a separate Publish function, this same function would listen for a reply from the server and take appropriate action when said message was received. On the server, the received message is checked to see if it is one of a list of known statements, if the statement is true, respond with the appropriate message, and update the communications suite. The communications suite would consist of functions to update e-mail, text, Twitter and Facebook.

Page 5 of 71

Evaluation of the Zero MQ socket library

DT080B

For example, if the light level drops below a certain level, the system will Publish the message its dark, on the server side. When the message its dark is received, the server responds with the message turn on lights and updates the communications suite. On the client side, when the message turn on lights is received , the pi sends a voltage high out through assigned pin to activate an external light.

Page 6 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 2 What is ZeroMQ?


ZeroMQ (MQ/ZMQ) is a high-performance asynchronous messaging library aimed at use in scalable distributed or concurrent applications. It provides a message queue, but unlike message-oriented middleware, a ZeroMQ system can run without a dedicated message broker. The library is designed to have a familiar socket-style API (Hintjens, March 2013) Berkeley Sockets (BSD) are the de-facto API for all network communication. With roots from the early 1980's, it is the original implementation of the TCP/IP suite, and is one of the most widely supported and critical components of any operating system today. The BSD sockets that we are familiar with are peer-to-peer connections, which require explicit setup, teardown, choice of transport (TCP, UDP) ,error handling, and so on. Once you solve all of the above problems you are into the world of application protocols (ex: HTTP), which require additional framing, buffering, and processing logic. In other words, it is no wonder that a high-performance network application is difficult to write (Grigorik, 2010). The ZeroMQ networking library allows you to abstract some of the low-level details of different socket types, connection handling, framing, or even routing. ZeroMQ sockets provide a layer of abstraction on top of the traditional socket API, which allows it to hide much of the everyday complexity we are forced to repeat in applications. To begin, instead of being stream (TCP) or datagram (UDP) oriented, ZeroMQ communication is messageoriented. This means that if a client socket sends a 150kb message, then the server socket will receive a complete, identical message on the other end without having to implement any explicit buffering or framing. Of course, we could still implement a streaming interface, but doing so would require an explicit application-level protocol. (Grigorik, 2010) Switching from a streaming/datagram to a message-oriented model is a minor change but one that carries many implications. As ZeroMQ handles all of the buffering and framing,

the client and server applications become simpler, more secure, and much easier to write. "It gives you sockets that carry whole messages across various transports like inproc, IPC, TCP, and multicast; you can connect sockets N-to-N with patterns like fanout, pubsub, task distribution, and request-reply" .

Page 7 of 71

Evaluation of the Zero MQ socket library

DT080B

The ZeroMQ API provides sockets (a kind of generalisation over the traditional IP and Unix domain sockets), each of which can represent a many-to-many connection between endpoints. Operating with a message-wise granularity, they require that a messaging pattern be used, and are particularly optimized for that kind of pattern. The key differences to conventional sockets are that, generally speaking, conventional sockets present a synchronous interface to either connection-oriented reliable byte streams or connection-less unreliable datagrams. In comparison, 0MQ sockets present an abstraction of an asynchronous message queue, with the exact queuing details depending on the socket type in use. Where conventional sockets transfer streams of bytes or discrete datagrams, 0MQ sockets transfer discrete messages. 0MQ sockets, being asynchronous, mean that the timings of the physical connection setup and teardown, reconnection and delivery are transparent to the user and organized by 0MQ itself. Further to this, messages may be queued in the event that a peer is unavailable to receive them. Conventional sockets allow only strict one-to-one (two peers), many-to-one (many clients, one server), or in some cases one-to-many (multicast) relationships. With the exception of ZMQ::PAIR, 0MQ sockets may be connected to multiple endpoints using connect(), while simultaneously accepting incoming connections from multiple endpoints bound to the socket using bind(), thus allowing many-to-many relationships. Programming with ZeroMQ ZeroMQ as a library works through sockets by following certain network communication patterns. It is designed to work asynchronously, and that is where the MQ suffix to its name comes - from queuing messages before sending them. ZeroMQ offers four different types of transport for communication. These are: In-Process (INPROC): Local (in-process) communication transport. Inter-Process (IPC): Local (inter-process) communication transport. TCP: Unicast communication transport using TCP. PGM: Multicast communication transport using PGM.

Page 8 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 3 ZeroMQ Sockets

ZeroMQ Socket Types Conventional sockets allow only strict one-to-one (two peers), many-to-one (many clients, one server), or in some cases one-to-many (multicast) relationships. With the exception of ZMQ_PAIR, ZMQ sockets can be connected to multiple endpoints using zmq_connect(), while simultaneously accepting incoming connections from multiple endpoints bound to the socket using zmq_bind(), thus allowing many-to-many relationships ZeroMQ sockets being asynchronous means that the timings of the physical connection setup and tear down, reconnect and delivery, are transparent to the user and organized by ZeroMQ itself. Further, messages may be queued in the event that a peer is unavailable to receive them. ZeroMQ sockets are not thread safe. Applications MUST NOT use a socket from multiple threads except after migrating a socket from one thread to another with a "full fence" memory barrier. This ensures that all load and store operations prior to the fence will have been committed prior to any loads and stores issued following the fence ( iMatix Corporation, 2012).

Socket types: To recap briefly what ZeroMQ does, it routes and queues messages according to precise recipes called patterns. These patterns provide ZeroMQ's intelligence. ZeroMQ's patterns are hard-coded and are implemented by pairs of sockets with matching types. In other words, to understand ZeroMQ patterns you need to understand socket types and how they work together. The following present the socket types defined by ZeroMQ, grouped by the general messaging pattern, which is built from related socket types. The way these sockets work depend on the type of socket chosen and the flow of messages being sent depends on the chosen patterns.

Page 9 of 71

Evaluation of the Zero MQ socket library

DT080B

The socket combinations that are valid for a connect-bind pair (either side can bind): PUB and SUB REQ and REP REQ and ROUTER DEALER and REP DEALER and ROUTER DEALER and DEALER ROUTER and ROUTER PUSH and PULL PAIR and PAIR

Sockets have life in four parts, just like BSD sockets:


Creating and destroying sockets (zmq_socket(), zmq_close()). Configuring sockets by setting options on them and checking them if necessary (zmq_setsockopt(),zmq_getsockopt()). Plugging sockets into the network topology by creating ZeroMQ connections to and from them (zmq_bind(), zmq_connect()). Using the sockets to carry data by writing and receiving messages on them (zmq_send(),zmq_recv()).

Note: that sockets are always void pointers and messages are structures. So sockets are passed as such, in all functions that work with messages, like zmq_send() and zmq_recv(). Creating, destroying, and configuring sockets works as you would expect for any object. The ZMQ_HWM option sets the high water mark for the specified socket. The high water mark is a hard limit on the maximum number of outstanding messages ZeroMQ will queue in memory for any single peer that the specified socket is communicating with. If this limit has been reached the socket enters an exceptional state and depending on the socket type, ZeroMQ takes appropriate action such as blocking or dropping sent messages( iMatix Corporation, 2012).

Page 10 of 71

Evaluation of the Zero MQ socket library ZMQ_REQ Socket:

DT080B

A socket of type ZMQ_REQ is used by a client to send requests to and receive replies from a service. This socket type allows only an alternating sequence of zmq_send(request) and subsequent zmq_recv(reply) calls. Each request sent is round robined among all services, and each reply received is matched with the last issued request. When a ZMQ_REQ socket enters an exceptional state due to having reached the high water mark for all services, or if there are no services at all, then any zmq_send() operations on the socket shall block until the exceptional state ends or at least one service becomes available for sending; messages are not discarded. ( iMatix Corporation, 2012)
Table 1 ZMQ REQ Charachteristics

Summary of ZMQ_REQ characteristics

Compatible peer sockets Direction Send/receive pattern Outgoing routing strategy Incoming routing strategy

ZMQ_REP Bidirectional Send, Receive, Send, Receive, Round-robin Last peer

ZMQ_HWM option action ( iMatix Corporation, 2012)

Block

Page 11 of 71

Evaluation of the Zero MQ socket library ZMQ_REP Socket:

DT080B

A socket of type ZMQ_REP is used by a service to receive requests from and send replies to a client. This socket type allows only an alternating sequence of zmq_recv(request) and subsequent zmq_send(reply) calls. Each request received is fair-queued from among all clients, and each reply sent is routed to the client that issued the last request. If the original requester doesn't exist anymore the reply is silently discarded. When a ZMQ_REP socket enters an exceptional state due to having reached the high water mark for a client, then any replies sent to the client in question shall be dropped until the exceptional state ends.
Table 2 ZMQ REP Charachteristics

Summary of ZMQ_REP characteristics

Compatible peer sockets Direction

ZMQ_REQ Bidirectional Receive, Send, Receive, Send, Fair-queued Last peer Drop

Send/receive pattern

Incoming routing strategy Outgoing routing strategy ZMQ_HWM option action (iMatix Corporation, 2012)

Page 12 of 71

Evaluation of the Zero MQ socket library ZMQ_PUB socket:

DT080B

A socket of type ZMQ_PUB is used by a publisher to distribute data. Messages sent are distributed in a fan out fashion to all connected peers. The zmq_recv() function is not implemented for this socket type. When a ZMQ_PUB socket enters an exceptional state due to having reached the high water mark for a subscriber, then any messages that are sent to the subscriber in question shall instead be dropped until the exceptional state ends. The zmq_send() function shall never block for this socket type.
Table 3 ZMQ PUB Charachteristics

Summary of ZMQ_PUB characteristics Compatible peer sockets Direction Send/receive pattern ZMQ_SUB Unidirectional Send only

Incoming routing strategy Outgoing routing strategy ZMQ_HWM option action (iMatix Corporation, 2012)

N/A Fan out Drop

Page 13 of 71

Evaluation of the Zero MQ socket library ZMQ_SUB socket:

DT080B

A socket of type ZMQ_SUB is used by a subscriber, to subscribe to data distributed by a publisher. Initially a ZMQ_SUB socket is not subscribed to any messages, use the ZMQ_SUBSCRIBE option of zmq_setsockopt() to specify which messages to subscribe to.
The zmq_send() function is not implemented for this socket type. Table 4 ZMQ SUB Charachteristics

Summary of ZMQ_SUB characteristics Compatible peer sockets Direction Send/receive pattern Incoming routing strategy ZMQ_PUB Unidirectional Receive only Fair-queued

Outgoing routing strategy ZMQ_HWM option action ( iMatix Corporation, 2012)

N/A Drop

Page 14 of 71

Evaluation of the Zero MQ socket library ZMQ_PUSH

DT080B

A socket of type ZMQ_PUSH is used by a pipeline node to send messages to downstream pipeline nodes. Messages are round-robined to all connected downstream nodes. The zmq_recv() function is not implemented for this socket type. When a ZMQ_PUSH socket enters an exceptional state due to having reached the high water mark for all downstream nodes, or if there are no downstream nodes at all, then any zmq_send() operations on the socket shall block until the exceptional state ends or at least one downstream node becomes available for sending; messages are not discarded. Deprecated alias: ZMQ_DOWNSTREAM.
Table 5 ZMQ PUSH Charachteristics

Summary of ZMQ_PUSH characteristics

Compatible peer sockets Direction Send/receive pattern Incoming routing strategy Outgoing routing strategy

ZMQ_PULL Unidirectional Send only N/A Round-robin

ZMQ_HWM option action (iMatix Corporation, 2012)

Block

Page 15 of 71

Evaluation of the Zero MQ socket library ZMQ_PULL

DT080B

A socket of type ZMQ_PULL is used by a pipeline node to receive messages from upstream pipeline nodes. Messages are fair-queued from among all connected upstream nodes. The zmq_send() function is not implemented for this socket type. Deprecated alias: ZMQ_UPSTREAM.
Table 6 ZMQ PULL Characteristics

Summary of ZMQ_PULL characteristics Compatible peer sockets Direction ZMQ_PUSH Unidirectional

Send/receive pattern Incoming routing strategy Outgoing routing strategy ZMQ_HWM option action ( iMatix Corporation, 2012)

Receive only Fair-queued N/A N/A

Page 16 of 71

Evaluation of the Zero MQ socket library ZMQ_DEALER

DT080B

A socket of type ZMQ_DEALER is an advanced pattern used for extending request/reply sockets. Each message sent is round-robined among all connected peers, and each message received is fair-queued from all connected peers. When a ZMQ_DEALER socket enters an exceptional state due to having reached the high water mark for all peers, or if there are no peers at all, then any zmq_send() operations on the socket shall block until the exceptional state ends or at least one peer becomes available for sending; messages are not discarded. When a ZMQ_DEALER socket is connected to a ZMQ_REP socket, each message sent must consist of an empty message part, the delimiter, followed by one or more body parts.
Table 7 ZMQ Dealer Characteristics

Summary of ZMQ_DEALER characteristics Compatible peer sockets Direction ZMQ_ROUTER, ZMQ_REQ, ZMQ_REP Bidirectional

Send/receive pattern Outgoing routing strategy Incoming routing strategy ZMQ_HWM option action ( iMatix Corporation, 2012)

Unrestricted Round-robin Fair-queued Block

Page 17 of 71

Evaluation of the Zero MQ socket library ZMQ_ROUTER

DT080B

A socket of type ZMQ_ROUTER is an advanced pattern used for extending request/reply sockets. When receiving messages the socket pre-appends a message part containing the identity of the originating peer to the message before passing it to the application. Messages received are fair-queued from among all connected peers. When sending messages a ZMQ_ROUTER removes the first part of the message and uses it to determine the identity of the peer that the message shall be routed to. If the peer does not exist anymore, the message is silently discarded. When a ZMQ_ROUTER socket enters an exceptional state of the high water mark for all peers, or if there are no peers at all, then any messages sent to the socket shall be dropped until the exceptional state ends. Likewise, any messages routed to a non-existent peer or a peer for which the individual high water mark has been reached shall also be dropped. When a ZMQ_REQ socket is connected to a ZMQ_ROUTER socket, in addition to the identity of the originating peer, each message received shall contain an empty delimiter message part. Hence, the entire structure of each received message as seen by the application becomes: one or more identity parts, delimiter part, one or more body parts, all replies to a ZMQ_REQ socket must include the delimiter part.
Table 8 ZMQ Router Characteristics

Summary of ZMQ_ROUTER characteristics Compatible peer sockets ZMQ_DEALER, ZMQ_REQ, ZMQ_REP

Direction Send/receive pattern Outgoing routing strategy Incoming routing strategy ZMQ_HWM option action

Bidirectional Unrestricted See text Fair-queued Drop

Page 18 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 5 ZMQ Pattern Examples:


Messaging pattern is a network-oriented architectural pattern, which describes how two different parts of a message passing system connect and communicate with each other. The following are the three main patterns used in building an application from ZeroMQ Each section shall have a brief explanation, a diagram and some python code (Java language examples are available on the appendix CD). There is also a brief example of a dealer router implementation 1. Request/Reply Pattern: The request-reply pattern is used for sending requests from a client to one or more instances of a service, and for also receiving subsequent replies to each request sent.
Figure 1Request Reply Pattern

(Hintjens, March 2013) In the above example the CLIENT sends the message Hello. The SERVER sends a World back The REQ socket can send a message, but must not send anything else until it gets a response or ZMQ will error. Likewise a REP socket cannot send a message unless it first receives one.

Page 19 of 71

Evaluation of the Zero MQ socket library


Figure 2 REP-REQ Pattern Client Python Code

DT080B

# Server import zmq context = zmq.Context() # Socket to talk to server print("Connecting to hello world server") socket = context.socket(zmq.REP) socket.bind("tcp://*:5555") while True: print("waiting for client request") msg = socket.recv() print("Message received %s % msg)message = socket.send("World )
Figure 3 REP-REQ Server Python Code

# Client import zmq context = zmq.Context() print("Connecting to hello world server") socket = context.socket(zmq.REQ) socket.connect("tcp://localhost:5555") for request in range(10): print("Sending request % s " % request) socket.send("Hello") # Get the reply. message = socket.recv() print("Received reply % s [ % s ]" %(request, message))

Page 20 of 71

Evaluation of the Zero MQ socket library 2. Publish/Subscribe Pattern

DT080B

The Publish-Subscribe Pattern is used for one-to-many distribution of data from a single publisher to multiple subscribers in a fan out fashion.
Figure 4 Publish Subscribe

(Hintjens, March 2013) Some points about the Publish-Subscribe (PUB-SUB) pattern:

A subscriber can connect to more than one publisher using one connect call each time. Data will then arrive and be interleaved, "fair-queued", so that no single publisher drowns out the others.

If a publisher has no connected subscribers then it will simply drop all messages. If using TCP and a subscriber is slow, messages will queue up on the publisher. Publishers are protected against this using the "high-water mark" in sockets.

Page 21 of 71

Evaluation of the Zero MQ socket library

DT080B

Figure 5 PUB-SUB Publisher Python Code

import zmq from random import randint context = zmq.Context() socket = context.socket(zmq.PUB) socket.bind("tcp://*:5556") while True: zipcode = randint(1, 10) temperature = randint(-20, 50) humidity = randint(10, 15) print Publish data:,(zipcode,temperature, humidity) socket.send("% d % d % d" % (zipcode,temperature, relhumidity))
Figure 6 PUB-SUB Subscriber Python Code

import zmq import sys context = zmq.Context() socket = context.socket(zmq.SUB) socket.connect("tcp://localhost:5556") zip_filter = sys.argv[1] if len(sys.argv) > 1 else print Collectin updates from weather service%s % zip_filter socket.setsockopt(zmq.SUBSCRIBE, zip_filter) #process 5 records for record in range(5): data = socket.recv()

Page 22 of 71

Evaluation of the Zero MQ socket library 3. Pipeline Pattern

DT080B

The Pipeline Pattern is used for distributing data to nodes arranged in a pipeline. Data always flows down the pipeline and each stage of the pipeline is connected to at least one node. When a pipeline stage is connected to multiple nodes data is round-robined among all connected nodes.
Figure 7 parallel pipeline

(Hintjens, March 2013) The workers connect upstream to the ventilator and downstream to the sink. This means you can add workers arbitrarily. If the workers are bound to their endpoints, you would need (a) more endpoints and (b) to modify the ventilator and/or the sink each time you added a worker. We say that the ventilator and sink are stable parts of our architecture and the workers are dynamic parts of it. We have to synchronize the start of the batch with all workers being up and running. This is a fairly common gotcha in ZeroMQ and there is no easy solution. The ZMQ_connect Page 23 of 71

Evaluation of the Zero MQ socket library

DT080B

method takes a certain amount of time. So when a set of workers connect to the ventilator, the first one to successfully connect will get a whole load of messages in that short time while the others are also connecting. If you don't synchronize the start of the batch somehow, the system won't run in parallel at all. Try removing the wait in the ventilator, and see what happens. The ventilator's PUSH socket distributes tasks to workers evenly, assuming they are all connected before the batch starts going out. This is called load balancing and it's something that will be addressed below in more detail. The sink's PULL socket collects results from workers evenly. This is called fair-queuing.

Page 24 of 71

Evaluation of the Zero MQ socket library


Figure 8 Ventilator Code Python Example

DT080B

# Task ventilator # Binds PUSH socket to tcp://localhost:5557 # Sends batch of tasks to workers via that socket # # Author: Lev Givon <lev(at)columbia(dot)edu> import zmq import random import time try: raw_input except NameError: # Python 3 raw_input = input context = zmq.Context() # Socket to send messages on sender = context.socket(zmq.PUSH) sender.bind("tcp://*:5557") # Socket with direct access to the sink: used to syncronize start of batch sink = context.socket(zmq.PUSH) sink.connect("tcp://localhost:5558") print("Press Enter when the workers are ready: ") _ = raw_input() print("Sending tasks to workers") # The first message is "0" and signals start of batch sink.send(b'0') # Initialize random number generator random.seed() # Send 100 tasks total_msec = 0 for task_nbr in range(100): # Random workload from 1 to 100 msecs workload = random.randint(1, 100) total_msec += workload sender.send_string(u'%i' % workload) print("Total expected cost: %s msec" % total_msec) # Give 0MQ time to deliver time.sleep(1)
( iMatix Corporation, 2012)

Page 25 of 71

Evaluation of the Zero MQ socket library


Figure 9 Worker Code In Python

DT080B

# Task worker # Connects PULL socket to tcp://localhost:5557 # Collects workloads from ventilator via that socket # Connects PUSH socket to tcp://localhost:5558 # Sends results to sink via that socket # # Author: Lev Givon <lev(at)columbia(dot)edu> import sys import time import zmq context = zmq.Context() # Socket to receive messages on receiver = context.socket(zmq.PULL) receiver.connect("tcp://localhost:5557") # Socket to send messages to sender = context.socket(zmq.PUSH) sender.connect("tcp://localhost:5558") # Process tasks forever while True: s = receiver.recv() # Simple progress indicator for the viewer sys.stdout.write('.') sys.stdout.flush() # Do the work time.sleep(int(s)*0.001) # Send results to sink sender.send(b'')
( iMatix Corporation, 2012)

Page 26 of 71

Evaluation of the Zero MQ socket library

DT080B

Figure 10 Sink Code Python Example


# Task sink # Binds PULL socket to tcp://localhost:5558 # Collects results from workers via that socket # # Author: Lev Givon <lev(at)columbia(dot)edu> import sys import time import zmq context = zmq.Context() # Socket to receive messages on receiver = context.socket(zmq.PULL) receiver.bind("tcp://*:5558") # Wait for start of batch s = receiver.recv() # Start our clock now tstart = time.time() # Process 100 confirmations total_msec = 0 for task_nbr in range(100): s = receiver.recv() if task_nbr % 10 == 0: sys.stdout.write(':') else: sys.stdout.write('.') sys.stdout.flush() # Calculate and report duration of batch tend = time.time() print("Total elapsed time: %d msec" % ((tend-tstart)*1000)) ( iMatix Corporation, 2012)

Page 27 of 71

Evaluation of the Zero MQ socket library

DT080B

4. Dealer Router Multithreading


Figure 11 Dealer Router Multithreading:

(Hintjens, March 2013) In the above example, the CLIENT sends a message to ROUTER and waits for a response. The ROUTER then processes message and sends to some Worker via the DEALER. The DEALER sends a message to Worker and waits for one response. The WORKER processes the message and sends a response back. The DEALER gets the message from WORKER, sends along to ROUTER. The ROUTER gets message and sends back to CLIENT, and the CLIENT does something with it!

Page 28 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 6 Implementation Motion sensor


It was decided to use a Request Reply ZeroMQ pattern as each input from the sensors would require action. For example, if a motion was detected the pi would be required to turn on a light/sound a buzzer. The a 5V Passive Infrared (PIR) motion sensor was wired to the pi as shown in Figure 12.The motion sensor sets a single output pin High whenever it detects movement within its field of view. It holds this pin High (3.3V) for a minimum period. If continuous movement is detected the output pin will stay high. When the time has elapsed and no more movement is detected the output pin returns Low (0V). Both time and sensitivity are adjustable on the sensor.

Figure 12 Motion sensor

On the Raspberry PI the a program was written to monitor the pin on which the motion sensor was connected when this pin goes high a Publish Function is called, This Publish function enacts a Zmq context, binds to the server address and sends a message . It waits or listens for a reply. When the reply is received the system returns to the monitoring state. Highlighted in Figure 13 below is the code for the main motion detector monitoring function and in Figure 14 is the code for the publish function.

Page 29 of 71

Evaluation of the Zero MQ socket library


Figure 13 Client Code Main Program
import re ,os, sys, time import zmq import RPi.GPIO as GPIO GPIO.cleanup() # Use BCM GPIO references # instead of physical pin numbers GPIO.setmode(GPIO.BCM) def main(): # Define GPIO to use on Pi GPIO_PIR = 24 print "PIR Module Test (CTRL-C to exit)" # Set pin as input GPIO.setup(GPIO_PIR,GPIO.IN) # Echo Current__State = 0 Previous_State = 0 #try defining motion try: print "Waiting for PIR to settle ..." # Loop until PIR output is 0 #PIR Warm up time while GPIO.input(GPIO_PIR)==1: Current_State = 0 print 'Ready' # Loop until users quits with CTRL-C while True : # Read PIR state Current_State = GPIO.input(GPIO_PIR) if Current_State==1 and Previous_State==0: # PIR is triggered print " Motion detected!" #call Publish function and pass the text motion Publish("Motion") # Record previous state Previous_State=1 elif Current_State==0 and Previous_State==1: # PIR has returned to ready state print " Ready" Previous_State=0 # Wait for 10 milliseconds time.sleep(0.01) # Keyboard interrupt Error catching except KeyboardInterrupt: print " Quit" # Reset GPIO settings GPIO.cleanup() return if __name__ == "__main__": main()

DT080B

Page 30 of 71

Evaluation of the Zero MQ socket library


Figure 14 Client Code Publish Function
def Publish(Text): #Set context context = zmq.Context() #Set the passed in variable to str str = Text #bind to server addreess bind_to = "tcp://192.168.2.6:5555" # Socket to talk to server print("Connecting to server") #set socket tho zmq Socket context REQ socket = context.socket(zmq.REQ) #connect to the server addreess socket.connect(bind_to) #Print the message being sent print("Sending request %s " % str) #send Message str socket.send(str) # Get the reply message = socket.recv() # Print the Reply print("Received reply %s " % (message)) # set reply equal to X X = message # Use x to print message. if X == "Detected": print "Turning on light " else: print "ERROR: Unexpected Message" return

DT080B

Figure 15 Server Code


def Server(): #start of ZmQ Server or main program #Create context object to a zmq Context context = zmq.Context() #Set socket contex to Rep, for a REQ-REP socket socket = context.socket(zmq.REP) #Bind Socket to "tcp://Localhost:Portnumber" socket.bind("tcp://192.168.2.5:5561") #loop ctrl-c while True: # Wait for next request from client message = socket.recv() #Print The message to the screen print "Received request: ", text # Do some 'work' time.sleep (1) # Do some 'work' # Send reply back to client socket.send("Detected")

Page 31 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 7 Implementation Twitter


In order to use the Twitter API (the interface that is used to post new Tweets and interact with Twitter from an external source), it was required to register as a developer and create a new app. This was done at https://dev.twitter.com/ . By default, the app is set to readonly so it was changed to Read and Write to allow posts to the twitter feed. Four sets of access tokens are required to log in and post. These are: consumer key, consumer secret, access key and access secret. These where generated in the developers section of Twitter and inputted into the function, as seen below in Figure 17. It was discovered that a repetitive message on Twitter throws an error., To overcome this the current time was added to the message posted. The function Tweet is called in the server code as seen below in Figure 16 and the text motion detected is passed to the funct ion:
Figure 16 Tweet Function Call
if text == "Motion": #Pass variables to functions and set text to Tweet("Motion Detected @ ") socket.send("Detected")

Figure 17 Twitter Function Code


def Tweet(Text): #set the localtime variable localtime = time.asctime( time.localtime(time.time())) #Set The message variable"msg" = The alert plus localTime, msg = Text+(localtime) #Twitter Access Keys CONSUMER_KEY = 'RbwVNyNI25q3U1y2TKhdw' CONSUMER_SECRET = '09dK2OkqVuVo9I12mUzltm01gi4YtnTXSZfvLwpA4' ACCESS_KEY = '2317027770-HgSg4Q4Xn4uzDpZwKpABUz67QxFVb8ah57LB51D' ACCESS_SECRET = 'a8FiPxgpbBif93qaUQpa3w5zaq0bq6KizUkvV8SDnJZZn' #Use Twython api To sign in to twitter api = Twython(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_KEY,ACCESS_SECRET) try: #Update satus api.update_status(status=msg )

# error handling except TwythonError as e: print e This was tested first on in Linux then on the Raspberry Pi before being implemented by the motion sensor. The results are below in Figure 18 Page 32 of 71

Evaluation of the Zero MQ socket library

DT080B

Figure 18 Tweet Results

Page 33 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 8 Implementation Analogue sensors


Now that the basic system was functioning the extra sensors were added. The Raspberry PI computer does not have a way to read analogue inputs. It is a digitalonly computer. The temperature and light sensor for the home monitoring system are analogue so a way to make the Pi analogue-friendly was needed. This was achieved by using the SPI bus on the Raspberry PI and a MCP3008 analogue to digital converter (ADC). In the SPI BUS, devices communicate using a master/slave relationship in which the master initiates the data frame. When the master generates a clock and selects a slave device, data may be transferred in either or both directions simultaneously. In fact, as far as SPI is concerned, data is always transferred in both directions. It is up to the master and slave devices to know whether a received byte is meaningful or not. So a device must discard the received byte in a "transmit only" frame or generate a dummy byte for a "receive only" frame.
Figure 19 Single Master Slave Implementation

(Kalinsky, 2002) SPI specifies four signals: clock (SCLK); master data output, slave data input (MOSI); master data input, slave data output (MISO); and slave select (SS),Figure 19 shows these signals in a single-slave configuration. SCLK is generated by the master and input to all slaves. MOSI carries data from master to slave. MISO carries data from slave back to master. A slave device is selected when the master asserts its CSS
In addition to these wires we have n wires for n slave devices on the bus. Each one of these wires carries the these wires carries the chip select signal (S S or CS ) for its respective device. Only one slave device can have its slave device can have its chip select signal asserted by the master controller at a time. These relationships are These relationships are illustrated in

Figure 20 Single Master, Multiple Slave Implementation.

Page 34 of 71

Evaluation of the Zero MQ socket library

DT080B

Figure 20 Single Master, Multiple Slave Implementation

(Kalinsky, 2002) The operation of the SPI bus is conceptually simple. Both the master controller and each slave device contain a shift register. When the chip select signal of a slave device is asserted (usually by being pulled low), the MISO wires are used to connect its shift register with that of the master device. Clock pulses are then generated by the master device, to shift data between the two shift registers enabling communication. In this sense the read and write operation are combined. For example, by shifting the contents of the master device shift register to that of the slave device, we are also shifting the data in the slave device shift register to that of the master.
Figure 21 Shifting from Master to Slave

Page 35 of 71

Evaluation of the Zero MQ socket library

DT080B

Finally, there are 4 different SPI modes that can be used. Each mode defines a particular clock phase (CPHA) and polarity (CPOL) with respect to the data. In this project SPI mode 0 which is also known as mode (0,0) or mode (CPHA=0,CPOL=0) was used. (Al-Hertani., 2013). The Linux Kernel in recent Raspberry Pi Releases supports the SPI as a native device so doesnt require bit-banging. However, as its disabled by default it needs to load the module before we can use the SPI device. Additionally the permissions and/or ownerships of the files in /dev/ need to be changed so that they can be accessed from out programs without needing to be root or run them with sudo. The MCP3008 chip is an SPI based analogue to digital converter (ADC). It has 8 analogue input channels that can be configured for single ended and differential ADC conversions. The MCP3008 is a 10-bit ADC that can convert 200 kilo samples per second (200ksps).
Figure 22 MCP3008 Pin Out

(Microchip, n.d.) As shown in Figure 23 the VDD pin was connected to the 3.3V power source from the Raspberry PI. The AGND (Analog ground) and DGND (Digitalground) pins were connected directly to ground as a reference point. The VREF pin is the reference voltage, which is the largest possible voltage that the ADC can interpret. The largest voltage the Raspberry pi can accept is 3.3V so the VREF pin was connected to 3.3V. So if 3.3V is Page 36 of 71

Evaluation of the Zero MQ socket library

DT080B

sampled on any of the ADCs channels it would be interpreted as the maximum digital value that can be represented by this 10-bit ADC (i.e. 2). Similarly, the

smallest analogue voltage that the ADC can detect (also known as the LSB size) is , which in this case is , represents a digital value of 1. The

equation that converts between the analogue voltage and its digital interpretation is given by: where VIN is the analogue input voltage

and VREF is the reference voltage. (Al-Hertani., 2013)


Figure 23 Setup of Analogue Sensors

To check the setup and implementation of the sensors, a convert temps, convert volts and read channel functions were added to the client as seen in Figure 24 , and the code in

Figure 25 was added to the main program. Figure 24 Analogue Sensor code
# Analogue Sensor Input ###################################################### #resets all ports back to input mode GPIO.cleanup() # Open SPI bus spi = spidev.SpiDev() spi.open(0,0) # Use BCM GPIO references instead of physical pin numbers # referring to the pins by the "Broadcom SOC channel" number GPIO.setmode(GPIO.BCM) # Function to read SPI data from MCP3008 chip # Channel must be an integer 0-7(8 total inputs) def ReadChannel(channel): adc = spi.xfer2([1,(8+channel)<<4,0]) data = ((adc[1]&3) << 8) + adc[2]

Page 37 of 71

Evaluation of the Zero MQ socket library


return data # Function to convert data to voltage level, # rounded to specified number of decimal places. def ConvertVolts(data,places): volts = (data * 3.3) / float(1023) volts = round(volts,places) return volts # Function to calculate temperature from # TMP36 data, rounded to specified # number of decimal places. def ConvertTemp(data,places): # ADC Value # (approx) Temp Volts # 0 -50 0.00 # 78 -25 0.25 # 155 0 0.50 # 233 25 0.75 # 310 50 1.00 # 388 75 1.25 # 465 100 1.50 # 543 125 1.75 # 620 150 2.00 # 698 175 2.25 # 775 200 2.50 # 853 225 2.75 # 930 250 3.00 # 1008 275 3.25 # 1023 280 3.30 temp = ((data * 330)/float(1023))-50 temp = round(temp,places) return temp # Define sensor channels light_channel = 0 temp_channel = 1 # Define delay between readings delay = 5

DT080B

Figure 25 Code to Read from analogue sensors


# Read the light sensor data light_level = ReadChannel(light_channel) light_volts = ConvertVolts(light_level,2) # Read the temperature sensor data temp_level = ReadChannel(temp_channel) temp_volts = ConvertVolts(temp_level,2) temp = ConvertTemp(temp_level,2) # When temp below approx 11 Degrees if temp_level <180: print "Brrr It's Cold" Publish("Cold") # When temp above approx 30 Degrees if temp_level >300: print "Dam Its hot" Publish("Hot") # From trial and error Dark Room if light_level<1000: print "Its Dark" Publish("Dark") # Wait for 10 milliseconds

Page 38 of 71

Evaluation of the Zero MQ socket library


time.sleep(0.01)

DT080B

Page 39 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 9 Implementation Adding the camera


The Raspberry Pi camera was added to the system setup and tested as per instructions on http://www.raspberrypi.org/camera . This enables the sending of photos and videos from the Pi sensor array. A function was added to the client to allowed the capture of pictures, see Figure 26, this allowed a photo to be captured by calling CapturePic(). The same file name is used and the image is overwritten each time. As the image will be Tweeted, e-mailed and Facebooked, it does not require unique saving.
Figure 26 Capture Pic Code
def CapturePic(): # Explicitly open a new file called my_image.jpg # wb is open as write binary my_file = open('my_image.jpg', 'wb') #the with keyword is used when working with unmanaged resources (like file streams) it ensures resources are cleaned up afterwards. with picamera.PiCamera() as camera: camera.start_preview() time.sleep(2) camera.capture(my_file) # Note that at this point the data is in the file cache, but may # not actually have been written to disk yet my_file.close() # Now the file has been closed, other processes should be able to # read the image successfully

The addition of pictures to the message proved a challenge. The message is sent as a string. The text is already a string, and converting temperature and light from integers to strings are quite simple. Adding the image was difficult but a solution was found in converting every pixel of the image into a hexadecimal word and the base 64 library. The base 64 algorithms is used for encoding and decoding arbitrary binary strings into text strings .This enabled the system to have 4 separate text strings: a text string of the image, a standard text string, temperature string, and light levels string. The next problem was how to combine all these strings and then separate them on the other side. To combine strings In Python you simply add them, for example string1 + string 2 = new string. But in order to separate them a unique character is required to split. After some research it was found that : is unique . Thus, to combine the strings into a separable message became msg = text +":"+ image +":"+light+":"+temp: and to split them the message is split at (":"). Thus text, image, light, temp = message.split(":"), this splits the

Page 40 of 71

Evaluation of the Zero MQ socket library

DT080B

message at : and puts each element into its relative variable. For example, the received message is some text: an Image :Light level: a Temperature : . The image is then re-encoded into an image from a string using base64.The variables and image are used for decision-making, and are passed into the various functions.

Figure 27 client Code


light_level = ReadChannel(light_channel) temp_level = ReadChannel(temp_channel) temp = ConvertTemp(temp_level,2) #camm camera function CapturePic() #open file "my_image.jpg" and rb read binary as imageFile with open("my_image.jpg", "rb") as imageFile: #convert image to string img = base64.b64encode(imageFile.read()) #print img #set socket contex context = zmq.Context() #convert light to string light = str(light_level) #convert temp to string tm = str(temp) #set the text element of message text = Text #Combine strings into msg msg = text +":"+ img +":"+light+":"+tm #bind to server addreess bind_to = "tcp://192.168.2.5:5561" print("Connecting to server") #Socket for talking to server socket = context.socket(zmq.REQ) #connect socket to bind_to Address socket.connect(bind_to) # Send request waiting each time for a response print"Sending ", text #send message socket.send(msg)

Page 41 of 71

Evaluation of the Zero MQ socket library


Figure 28 Server code
# Wait for next request from client message = socket.recv() #Split the recived message at: to seprate out the image , and variables from the string text, Image, light, temp = message.split(":") #Print variables to screen print "Received request: ", text print "The text is = ", text print "The Temp is = ", temp,"C" print "The Light is =", light," lumina" #uncomment below to see Image as a string #print "The Image is = ",Image #open image file in "wb" (writeable and binary mode). f = open("my_image.jpg", "wb") #Deccode back to an image from string using base64 f.write(Image.decode('base64')) # close file f.close()

DT080B

Figure 29 Results of Camera and analogue sensor addition

Page 42 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 10 Implementation Push Button and Outputs


A Push button switch was added to the system as seen in

Figure 30. To implement this, the following code was added to assign a BCM pin and a pin

mode:
Button = 25 satus = 0 print "PIR Module Test (CTRL-C to exit)" # Set pin as input GPIO.setup(PIR,GPIO.IN) #Set the button to input GPIO.setup(Button,GPIO.IN)

And the following was added to the If-Else output string in the client.
if GPIO.input(Button)==1: print "button pushed" Publish("Button")

Figure 30 Push button

Page 43 of 71

Evaluation of the Zero MQ socket library


Figure 31 Push button results

DT080B

The if else with all sensors in it now reads as seen in Figure 32


Figure 32 All Sensors IF Else
# Read PIR state if GPIO.input(PIR)==1: # PIR is triggered print " Motion detected!" Publish("Motion") # If button high (pushed) if GPIO.input(Button)==1: print "button pushed" Publish("Button") # When temp below approx 11 Degrees if temp_level <180: print "Brrr It's Cold" Publish("Cold") # When temp above approx 30 Degrees if temp_level >300: print "Dam Its hot" Publish("Hot") # From trial and error Dark Room if light_level>1000: print "Its Dark" Publish("Dark") # Wait for 10 milliseconds time.sleep(0.01)

Page 44 of 71

Evaluation of the Zero MQ socket library


Figure 33 Server If else all sensors:
#IF Else srting of possiable requests if text == "Motion": #Pass variables to functions and set text to Tweet("Motion Detected @ ",temp,light) time.sleep (1) #Send reply back to client socket.send("Detected") elif text == "Button": Tweet("Button Pressed @",temp,light) time.sleep(1) socket.send("Pressed") #condition for low light elif text == "Dark": Tweet("It's dark in Here @",temp,light) time.sleep (1) message = socket.recv() #Split the recived message at: to separate out the image , and variables from the string text, Image, light, temp = message.split(":") #Print variables to screen print "Received request: ", text print "The text is = ", text print "The Temp is = ", temp,"C" print "The Light is =", light," lumina" #uncomment below to see Image as a string #print "The Image is = ",Image #open image file in "wb" (writeable and binary mode). f = open("my_image.jpg", "wb") #Deccode back to an image from string using base64 f.write(Image.decode('base64')) # close file f.close() # Send reply back to client socket.send("LightOn") #conditon for Cold elif text == "Cold": Tweet("It's Cold In Here @",temp,light) time.sleep (1) #Send reply back to client socket.send("HeatOn") #Condition for Hot elif text == "Hot": Tweet("It's Getting Hot In Here @ ",temp,light) time.sleep (1) #Send reply back to client socket.send("FanOn") #Condition for timed satus update elif text == "Satus Update": Tweet("Satus Update From Pi @",temp,light) #Send reply back to client socket.send("Satus Recived") #If unknown message received reply else: # Do some 'work' time.sleep (1) # Send reply back to client print("Unknown Message") # Send reply back to unblock port if error socket.send("Unknown Message")

DT080B

Page 45 of 71

Evaluation of the Zero MQ socket library


Figure 34 Publish function:
#camm camera function CapturePic() #open file "my_image.jpg" and rb read binary as imageFile with open("my_image.jpg", "rb") as imageFile: #convert image to string img = base64.b64encode(imageFile.read()) #print img #set socket contex context = zmq.Context() #convert light to string light = str(light_level) #convert temp to string tm = str(temp) #set the text element of message text = Text #Combine strings into msg msg = text +":"+ img +":"+light+":"+tm #get the reply message = socket.recv() print ("Received Reply ", message) #copy message to X X = message #If Else String for returned value from server if X == "Detected": print "light led" time.sleep(1) elif X == "Pressed": print "sound alarm " elif X == "HeatOn": print "Turning on Heat " elif X == "FanOn": print "Turning on Fan " elif X == "LightOn": print "Turning on The lights " elif X == "Satus Updated": print "Satus updated" else: print "Did Nothing"

DT080B

Page 46 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 12 Implementation Outputs


Now that all sensors are connected, tested, and working, some outputs where added to the Pi. Although initially planned to be relay switches, it was found that the Pi produced insufficient current to drive these switches when all sensors where attached. Following extensive research, solutions were found but deemed impractical for this demonstration project. Thus, LEDs where used to represent these external items such as heaters, fans, lights etc. The LEDs where connected as shown in Figure 35 and a current limiting resistor was added to each one.
Figure 35 LED

The client code was updated to activate each LED, as its message arrives which can be seen in Figure 36.
Figure 36 LED Output code client
socket.send(msg) # Get the reply message = socket.recv() print ("Received Reply ", message) #copy message to X X = message #If Else String for returned value from server if X == "Detected": print "Turning on Red light " # Define GPIO pin to use on Pi GPIO_RLED = 17 print "Led Module Test (CTRL-C to exit)"

Page 47 of 71

Evaluation of the Zero MQ socket library


#Set Gpio Mode to output GPIO.setup(GPIO_RLED,GPIO.OUT) #Set value to high (LED on) GPIO.output(GPIO_RLED, True) #time for 5 sceonds time.sleep(5) #Set value to low (LED off) GPIO.output(GPIO_RLED, False) time.sleep(1) elif X == "Pressed": print "sound alarm " #Define GPIO to use on Pi GPIO_YLED = 22 print "Led Module Test (CTRL-C GPIO.setup(GPIO_YLED,GPIO.OUT) GPIO.output(GPIO_YLED, True) time.sleep(5) GPIO.output(GPIO_YLED, False) time.sleep(1) elif X == "HeatOn": print "Turning on Heat " elif X == "FanOn": print "Turning on Fan " print "Turning on Yellow light #Define GPIO to use on Pi GPIO_YLED = 18 print "Led Module Test (CTRL-C GPIO.setup(GPIO_YLED,GPIO.OUT) GPIO.output(GPIO_YLED, True) time.sleep(5) GPIO.output(GPIO_YLED, False) time.sleep(1) elif X == "LightOn": GPIO_GLED = 27 print "Led Module Test (CTRL-C GPIO.setup(GPIO_GLED,GPIO.OUT) GPIO.output(GPIO_GLED, True) time.sleep(5) GPIO.output(GPIO_GLED, False) time.sleep(1) print "Turning on The lights " elif X == "Satus Updated": print "Satus updated" else: print "Did Nothing"

DT080B

to exit)"

"

to exit)"

to exit)"

Page 48 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 13 Implementation Email


The e-mail package in python is a library for managing email messages including Multipurpose Internet Mail Extensions (MIME). As its name suggests, MIME is a set of extensions to standard internet e-mail. MIME has been in use for some time and it may now be safe to say that MIME is the standard for internet email. To implement the e-mail system, simply required an email account, username, address and password and a list of addresses for the message to be sent to, the SMTP host address and port number. This allows the sending e-mail address to login and allows a text only message to be sent. The Mine library allows the addition of attachments to this text message. The Mine library MimeMultipart allows multiple attachments, it divides the message into parts and each part has headers including the type of data, filename and encoding used. This finds the type of attachment and attaches it to the standard message. The coding for this is in Figure 38 and the results of this can be seen in Figure 39. To send an email, the Publish function calls the e-mail function and passes it a predefined text, temperature and light level. The e-mail program opens the image file from the disk itself as shown in Figure 37.
Figure 37 Calling Email function
if text == "Motion": #Pass variables to functions and set text to FaceBook("Motion Detected @",temp,light) Tweet("Motion Detected @ ",temp,light)

Figure 38 Email function


# Email function ###################################################### #Pass the variables into the email function def Email (Text,temp,light): #From Address Can be any address fromaddr = "alanspiproject2013@gmail.com" # Address To Must be a valid addresses tolist = "alanspiproject2013@gmail.com" # Message body text = Text+"\nCurrent Conditions"+"\nTemp is ="+temp+" Degrees C"+"\nLight Level is ="+light+" lumina" # Attachment location /path/to/file in this instance file is in same folder so name is sufficent filename = 'my_image.jpg' # Credentials username = "alanspiproject2013@gmail.com" password = "Al1981mat" #SMTP host address and port number host = 'smtp.gmail.com' port = 587 # Create a stmp object clled server

Page 49 of 71

Evaluation of the Zero MQ socket library

DT080B

server = smtplib.SMTP() #connect to smtp host server.connect( host,port) #start Transport Layer Security server.starttls() #Login to mail server server.login(username,password) #Sbject Field sub = ('Subject: Update From PI ') #Mimemultipart allows Multiple attachments Divides the message into parts, Each part has headers including the type of data, filename, encoding used msg = email.MIMEMultipart.MIMEMultipart() msg['From'] = fromaddr msg['To'] = toaddrs msg['Subject'] = sub msg.attach(MIMEText(text)) msg.attach(MIMEText('\nsent via python From PI Server', 'plain')) # 'plain ' is a plain text type #file import file as read only in bytewise process f = open(filename,'rb') #ctypy provides C compatible data types, and allows calling functions in DLLs or shared libraries. #load file and guess what it is. ctype, encoding = mimetypes.guess_type(filename) if ctype is None or encoding is not None: ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) if maintype == 'text': part = MIMEText(f.read(), _subtype=subtype) elif maintype == 'image': part = MIMEImage(f.read(), _subtype=subtype) elif maintype == 'audio': part = MIMEAudio(f.read(), _subtype=subtype) else: part = MIMEBase(maintype, subtype) msg.set_payload(f.read()) #attach the file part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(filename)) msg.attach(part) #close the file f.close() #send the mail server.sendmail(username,tolist,msg.as_string()) #Quit server server.quit() # code refrence http://docs.python.org/2/library/email-examples.html return

Page 50 of 71

Evaluation of the Zero MQ socket library


Figure 39 Email Results:

DT080B

Page 51 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 14 Implementation Text Messaging


To send a text message from the publish function, a text function was created and an internet based SMS service was used. After researching several different services, it was decided to use the TextLocal service (http://www.textlocal.com/). Although they did not have any python examples, they had extensive examples in other languages and allowed a certain number of development messages to be sent for free. The text function is called in the same way as the e-mail function, see Figure 37. The message is sent to the text local send URL along with a unique app hash code, this sends the message contents to a numbers list. The code seen below is adapted from a PHP example. This function was originally planned to be a multimedia messaging service but at this time text local did not offer this service to Irish numbers, only UK based mobile numbers.

Page 52 of 71

Evaluation of the Zero MQ socket library


Figure 40 Text Function Code

DT080B

#Function text taking in text , temp and light variables def Text (Text,temp,light): #This was originally meant to be an mms message service but mms is un available in ireland from this service. #There is no Python api for txtlocal(webbased sms service) this is adapted from a pHp version #set the localtime variable localtime = time.asctime( time.localtime(time.time()) ) #Set The message variable"str = The alert plus Time message = Text+(localtime)+"\nCurrent Conditions"+"\nTemp is =\t"+temp+"C"+"\nLight Level is =\t"+light+" lumina" # Set username and sender name. # Sender name between 3 and 11 characters in length username = "almat1981@gmail.com" sender = "Pi Project" # unique hash Gotten from textlocal Php program hash = "e373cafb7f4919f3b4f729781b2e7bb17e42cdc2" # Set the phone number you wish to send the # Multiple numbers separated by comma numbers = ("353872924405") message to.

# Set flag to 1 to simulate for testing # To send real message set this flag to 0 test_flag = 0 #PHP arrays are ordered mappings, so used a Python OrderedDict instead of a regular dict so that the order of insertion is preserved values = {"test" : test_flag, "uname" : username, "hash" : hash, "message" : message, "from" : sender, "selectednums" : numbers } #url texts are sent from url = "http://www.txtlocal.com/sendsmspost.php" #Convert a mapping object or a sequence of two-element tuples to a percentencoded string, suitable to pass to urlopen() postdata = urllib.urlencode(values) #Open the URL url, which is the Request object Postdata. req = urllib2.Request(url, postdata) #Try to send print "Attempt to send SMS ..." try: #Open the URL response = urllib2.urlopen(req) response_url = response.geturl() if response_url==url: print "SMS sent!" except urllib2.URLError, e: print "Send failed!" print e.reason return

Page 53 of 71

Evaluation of the Zero MQ socket library

DT080B

Page 54 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 15 Implementation Facebook


To post a message on a Facebook wall from an external system, a Facebook account is required. This account can generate an access token and app I.D. from the Facebook developers section.
Figure 41 Facebook Function
###################################################### # FACEBOOK WALL UPDATER ###################################################### # Variables ,Text,Temp, and light passed in from main (server ) program. def FaceBook(Text,temp,light): #Variable localtime set to current time using time module localtime = time.asctime( time.localtime(time.time())) #Contents of post message=Text+(localtime)+"\nCurrent Conditions"+"\nTemp is =\t"+temp+"C"+"\nLight Level is =\t"+light+" lumina" #FaceBook Api Access Token and App ID access_token='CAACEdEose0cBAMi7w6VtbzOO3DS2cQwK6MIc4Fx1CZBabqUJELzRT6NXAo CRrKZA9y7DpXzhQzVQmmqYeey7Te5U4mM3IG6pA10wOTanoxSr8JcxCzsstDDZByhBl279RoR He0Hn2hdxwI6XAMZBeKnmTo72wPZC6I8mD0bvaiguN4Mb0VabbEXdG4zn8A68ZD' FACEBOOK_APP_ID =100007647638324 #Create a FaceBook Graph object facebook_graph = facebook.GraphAPI(access_token) #Posting Text only To Wall To attach a pic must be registered as a developer. facebook_graph.put_wall_post(message,profile_id='me') print "Facebook Wall Updated"

Figure 42 FaceBook Wall Post

Page 55 of 71

Evaluation of the Zero MQ socket library

DT080B

Chapter 16 Discussion
ZeroMQ is not a message broker. It is often mistaken for one because of its name. What ZeroMQ is, is a library that supports certain network communication patterns using sockets. The "MQ" part comes in because ZeroMQ uses queues internally to buffer messages so that you do not block your application when sending data. When you say socket.send(...), ZeroMQ actually enqueues a message to be sent later by a dedicated communication thread. This communication thread and its state are encapsulated in the ZeroMQ context object. The ZeroMq system is an excellent high speed messaging library upon which to build your own broker. It is aimed at high volume speed critical applications where cost and saleability are paramount. As such it was probably a bad choice for a domestic monitoring system but would be a very good choice if one decides to design a program such as the next Twitter, for example. Despite this, even using it in this context could have been improved. In the client server REP REQ pattern, if the server and client had been swapped it would have allowed for greater flexibility. Currently the system detects motion (on the PI/Client), sends a message to the server and waits for response, blocking all ports. Whereas if swapped, upon power up a ready message would be sent to the PI (now server), and when the PI detects motion it sends the response to the external system (now Client), this then uses that message to do work (update the communications suite). 5. Ideally however, a dealer router pattern as seen in Dealer Router Multithreading
Figure 11 could have been used. This would have allowed full proper multi-threading inside

the system. In addition, I believe that it would have allowed much better performance and possibly for ZMQ to handle the social media aspect as well as just the machine to machine messaging. This however would have required writing the APIs from scratch. The python programing language is simple and powerful. It allows to be done is a few lines of code what would take hundreds of lines in C++ for example. The programs themselves are tiny in size compared to what the equivalent C++, or Java program would be. Both programs together are less than 20kb. This makes it ideal for programming in space sensitive areas.

Page 56 of 71

Evaluation of the Zero MQ socket library

DT080B

Conclusion
This project fulfils all the sections of the initial brief. It uses the Raspberry Pi as a monitoring system and uses Zmq to send a message to the server. The server controls what output will go to the Pi and through that server the system interacts with social media. As with any project of this type it is never complete, it can always be improved or refined but given the time constraints it performs well. As a learning experience, this project has been excellent. It allowed me to cover a lot of ground from learning about the Python programming language, message oriented

middleware, low end of the communication protocols, and the interaction of social media APIs.

Page 57 of 71

Evaluation of the Zero MQ socket library

DT080B

Bibliography
iMatix Available [Accessed 7 03 2014]. Al-Hertani., Available at: H., 2013. http://hertaville.com/. [Online] Corporation, 2012. at: MQ API Reference. [Online] http://api.zeromq.org/

http://hertaville.com/2013/07/24/interfacing-an-spi-adc-mcp3008-chip-to-the-

raspberry-pi-using-c/ [Accessed 07 01 2014]. Amy Brown, G. W., 08 May 2012. The Architecture of Open Source Applications, Volume II. 1st ed. California: Creative Commons: Attribution. Anon., n.d. [Online]

Available at: http://elinux.org/RPi_Low-level_peripherals Anon., Available at: n.d. [Online]

http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-

Peripherals.pdf Grigorik, Available at: I., 2010. http://www.igvita.com/. [Online]

http://www.igvita.com/2010/09/03/zeromq-modern-fast-networking-stack/

[Accessed 21 01 2014]. halherta, Available at: July 24, 2013 . http://hertaville.com/. [Online]

http://hertaville.com/2013/07/24/interfacing-an-spi-adc-mcp3008-chip-to-the-

raspberry-pi-using-c/ [Accessed 07 03 2014]. Hintjens, P., March 2013. ZeroMQ Messaging for Many Applications. 1st ed. Sebastopol, CA: O'Reilly Media. Kalinsky, Available D. K. at: a. R., 2002. embedded.com. [Online]

http://www.embedded.com/electronics-blogs/beginner-s-

corner/4023908/Introduction-to-Serial-Peripheral-Interface Microchip, n.d. MCP3004/3008 Data sheet. [Online]

Available at: http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf

Page 58 of 71

Evaluation of the Zero MQ socket library

DT080B

Scherfke, S., 2012. Designing and Testing PyZMQ Applications, Oldenburg, Germany: OFFIS Institute for Information Technology Oldenburg, Germany. Tezer, Available at: O., n.d. [Online]

https://www.digitalocean.com/community/articles/how-to-work-with-the-

zeromq-messaging- library

Appendices
MCP3008 DataSheet http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf TM36 Datasheet: http://www.analog.com/static/imported-files/data_sheets/TMP35_36_37.pdf

Figure 1Request Reply Pattern ............................................................................................ 19 Figure 2 REP-REQ Pattern Client Python Code ................................................................. 20 Figure 3 REP-REQ Server Python Code ............................................................................. 20 Figure 4 Publish SubScribe ................................................................................................. 21 Figure 5 PUB-SUB Publisher Python Code ........................................................................ 22 Figure 6 PUB-SUB Subscriber Python Code ...................................................................... 22 Figure 7 parallel pipeline ..................................................................................................... 23 Figure 8 Ventalator Code Python Example ......................................................................... 25 Figure 9 Worker Code In Python......................................................................................... 26 Figure 10 Sink Code Python Example................................................................................. 27 Figure 11 Dealer Router Multithreading: ............................................................................ 28 Figure 12 Motion sensor ...................................................................................................... 29 Figure 13 Client Code Main Program ................................................................................. 30 Page 59 of 71

Evaluation of the Zero MQ socket library

DT080B

Figure 14 Client Code Publish Function ............................................................................ 31 Figure 15 Server Code ......................................................................................................... 31 Figure 16 Tweet Function Call ............................................................................................ 32 Figure 17 Twitter Function Code ........................................................................................ 32 Figure 18 Tweet Results ...................................................................................................... 33 Figure 19 Single Master Slave Implementation .................................................................. 34 Figure 20 Single master, multiple slave implementation .................................................... 35 Figure 21 .............................................................................................................................. 35 Figure 22 MCP3008 Pin Out ............................................................................................... 36 Figure 23 Setup of Analogue Sensors ................................................................................. 37 Figure 24 Analogue Sensor code ......................................................................................... 37 Figure 25 Code to Read from analogue sensors .................................................................. 38 Figure 26 Capture Pic Code................................................................................................. 39 Figure 27 client Code........................................................................................................... 40 Figure 28 Server code .......................................................................................................... 41 Figure 29 Results of Camera and analogue sensor addition ................................................ 41 Figure 30 Push button .......................................................................................................... 42 Figure 31 Push button results .............................................................................................. 43 Figure 32 All Sensors IF Else .............................................................................................. 43 Figure 33 Server If else all sensors:..................................................................................... 44 Figure 34 Publish function: ................................................................................................. 45 Figure 35 LED ..................................................................................................................... 46 Figure 36 LED Output code client....................................................................................... 46 Figure 37 Calling Email function ........................................................................................ 48 Figure 38 Email function ..................................................................................................... 48 Figure 39 Email Results: ..................................................................................................... 50 Page 60 of 71

Evaluation of the Zero MQ socket library

DT080B

Figure 40 Text Function Code ............................................................................................ 52 Figure 41 Facebook Function .............................................................................................. 54 Figure 42 FaceBook Wall Post ............................................................................................ 54

Code: Client Code:


## #!/usr/bin/python # -*- coding: latin-1 -*# Alan Matthews # Rep Req Client #192.168.2.4location of all sensors and outputs # Connects REQ socket to tcp://localhost:5555 ######################################################################### ######################## # import os # import sys # import re # import io # import zmq # import RPi.GPIO as GPIO # import time #SPI(Serial Peripheral Interface bus) is a synchronous serial data link import spidev # import base64 # import picamera # import threading # import datetime ######################################################################### ####################### # Analogue Sensor Input ######################################################################### ###################### #resets all ports back to input mode GPIO.cleanup() # Open SPI bus spi = spidev.SpiDev() spi.open(0,0) # Use BCM GPIO references instead of physical pin numbers # referring to the pins by the "Broadcom SOC channel" number GPIO.setmode(GPIO.BCM) # Function to read SPI data from MCP3008 chip

Page 61 of 71

Evaluation of the Zero MQ socket library


# Channel must be an integer 0-7(8 total inputs) def ReadChannel(channel): adc = spi.xfer2([1,(8+channel)<<4,0]) data = ((adc[1]&3) << 8) + adc[2] return data # Function to convert data to voltage level, # rounded to specified number of decimal places. def ConvertVolts(data,places): volts = (data * 3.3) / float(1023) volts = round(volts,places) return volts # Function to calculate temperature from # TMP36 data, rounded to specified # number of decimal places. def ConvertTemp(data,places): # # # # # # # # # # # # # # # # # ADC Value (approx) 0 78 155 233 310 388 465 543 620 698 775 853 930 1008 1023 Temp -50 -25 0 25 50 75 100 125 150 175 200 225 250 275 280 Volts 0.00 0.25 0.50 0.75 1.00 1.25 1.50 1.75 2.00 2.25 2.50 2.75 3.00 3.25 3.30

DT080B

temp = ((data * 330)/float(1023))-50 temp = round(temp,places) return temp # Define sensor channels light_channel = 0 temp_channel = 1 # Define delay between readings delay = 5 def CapturePic(): # Explicitly open a new file called my_image.jpg my_file = open('my_image.jpg', 'wb') with picamera.PiCamera() as camera: camera.start_preview() time.sleep(2) camera.capture(my_file) # Note that at this point the data is in the file cache, but may # not actually have been written to disk yet my_file.close() # Now the file has been closed, other processes should be able to # read the image successfully def Publish(Text): light_level = ReadChannel(light_channel) temp_level = ReadChannel(temp_channel)

Page 62 of 71

Evaluation of the Zero MQ socket library


temp = ConvertTemp(temp_level,2) #camm camera function CapturePic() #open file "my_image.jpg" and rb read binary as imageFile with open("my_image.jpg", "rb") as imageFile: #convert image to string img = base64.b64encode(imageFile.read()) #print img #set socket contex context = zmq.Context() #convert light to string light = str(light_level) #convert temp to string tm = str(temp) #set the text element of message text = Text #Combine strings into msg msg = text +":"+ img +":"+light+":"+tm #bind to server addreess bind_to = "tcp://192.168.2.5:5561" print("Connecting to server") #changed from Req to Push #Socket for talking to server socket = context.socket(zmq.REQ) #connect socket to bind_to Address socket.connect(bind_to) # Send request waiting each time for a response print"Sending ", text #send message socket.send(msg) # Get the reply message = socket.recv() print ("Received Reply ", message) #copy message to X X = message #If Else String for returned value from server if X == "Detected": print "Turning on Red light " # Define GPIO pin to use on Pi GPIO_RLED = 17 print "Led Module Test (CTRL-C to exit)" #Set Gpio Mode to output GPIO.setup(GPIO_RLED,GPIO.OUT) #Set value to high (LED on) GPIO.output(GPIO_RLED, True) #time for 5 sceonds time.sleep(5) #Set value to low (LED off) GPIO.output(GPIO_RLED, False) time.sleep(1) elif X == "Pressed": print "sound alarm " #Define GPIO to use on Pi GPIO_YLED = 22 print "Led Module Test (CTRL-C to exit)" GPIO.setup(GPIO_YLED,GPIO.OUT) GPIO.output(GPIO_YLED, True) time.sleep(5) GPIO.output(GPIO_YLED, False) time.sleep(1)

DT080B

Page 63 of 71

Evaluation of the Zero MQ socket library


elif X == "HeatOn": print "Turning on Heat " elif X == "FanOn": print "Turning on Fan " print "Turning on Yellow light " #Define GPIO to use on Pi GPIO_YLED = 18 print "Led Module Test (CTRL-C to exit)" GPIO.setup(GPIO_YLED,GPIO.OUT) GPIO.output(GPIO_YLED, True) time.sleep(5) GPIO.output(GPIO_YLED, False) time.sleep(1) elif X == "LightOn": GPIO_GLED = 27 print "Led Module Test (CTRL-C to exit)" GPIO.setup(GPIO_GLED,GPIO.OUT) GPIO.output(GPIO_GLED, True) time.sleep(5) GPIO.output(GPIO_GLED, False) time.sleep(1) print "Turning on The lights " elif X == "Satus Updated": print "Satus updated" else: print "Did Nothing" def main(): # Define GPIO to use on Pi PIR = 24 Button = 25 satus = 0 print "PIR Module Test (CTRL-C to exit)" # Set pin as input GPIO.setup(PIR,GPIO.IN) #Set the button to input GPIO.setup(Button,GPIO.IN) Current__State = 0 Previous_State = 0 try: print "Waiting for PIR to settle ..." # Loop until PIR output is 0 while GPIO.input(PIR)==1: Current_State = 0 print 'Ready' # Loop until users quits with CTRL-C

DT080B

while True : #Set satus to false satus = 0 #Get the time and set variable equal to it upDateTime = datetime.datetime.now() #UpDate on the hour and half hour,(by adding day this could be set to any time or day) if (upDateTime.minute ==00 or upDateTime.minute ==30) and (upDateTime.second ==30): #set satus to true satus = 1 # Read the light sensor data

Page 64 of 71

Evaluation of the Zero MQ socket library


light_level = ReadChannel(light_channel) light_volts = ConvertVolts(light_level,2) # Read the temp_level temp_volts temp temperature sensor data = ReadChannel(temp_channel) = ConvertVolts(temp_level,2) = ConvertTemp(temp_level,2)

DT080B

# When The time is righ UpDate if satus==1: print "Time for Update" Publish("Satus Update") satus ==0 # Read PIR state if GPIO.input(PIR)==1: # PIR is triggered print " Motion detected!" Publish("Motion") # If button high (pushed) if GPIO.input(Button)==1: print "button pushed" Publish("Button") # When temp below approx 11 Degrees if temp_level <180: print "Brrr It's Cold" Publish("Cold") # When temp above approx 30 Degrees if temp_level >300: print "Dam Its hot" Publish("Hot") # From trial and error Dark Room if light_level>1000: print "Its Dark" Publish("Dark") # Wait for 10 milliseconds time.sleep(0.01) except KeyboardInterrupt: print " Quit" # Reset GPIO settings GPIO.cleanup() return if __name__ == "__main__": main()

Server Code:
#!/usr/bin.python # -*- coding: latin-1 -*# Author: Alan Matthews # PI Monitor server in Python # Binds REP socket to tcp://*:5555 # 02/03/14 # Added Exception handling # Version 0.1.3 ######################################################################### ###########################################

Page 65 of 71

Evaluation of the Zero MQ socket library

DT080B

#For more information on amy modules please see http://docs.python.org/2.7/ #The ZeroMQ Liblary import zmq #JSON (JavaScript Object Notation)used as a lightweight data interchange format import json #provides data encoding and decoding import base64 #This module provides various time-related functions import time #This module provides access to variables used or maintained by the interpreter and functions that interact with the interpreter. import sys #This module defines an SMTP client session object that can be used to send mail to any Internet machine with an SMTP import smtplib #This module provides a way of using operating system functionality.e.g to read or write a file import os #The email module is a library for managing email messages, including MIME import email #Python's email package contains many classes and functions for composing and parsing email messages #by only importing only the classes we need, this saves us from having to use the full module name later. from email.MIMEMultipart import MIMEMultipart from email.Utils import COMMASPACE from email.MIMEBase import MIMEBase from email.parser import Parser from email.MIMEImage import MIMEImage from email.MIMEText import MIMEText from email.MIMEAudio import MIMEAudio #For guessing MIME type based on file name extension import mimetypes #twython is a pure Python wrapper for the Twitter API. Supports both normal and streaming Twitter APIs from twython import Twython, TwythonError #Facebook graph Api import facebook #This module provides a high-level interface for fetching data across the World Wide Web. # module defines functions and classes which help in opening URLs and breaking URL strings up into components import urllib,urllib2,urlparse ######################################################################### ########################################### # FACEBOOK WALL UPDATER ######################################################################### ########################################### # Variables ,Text,Temp, and light passed in from main (server ) program. def FaceBook(Text,temp,light): #Variable localtime ste to current time using time module localtime = time.asctime( time.localtime(time.time())) #Contents of post message=Text+(localtime)+"\nCurrent Conditions"+"\nTemp is =\t"+temp+"C"+"\nLight Level is =\t"+light+" lumina" #FaceBook Api Access Token and App ID

Page 66 of 71

Evaluation of the Zero MQ socket library

DT080B

access_token='CAACEdEose0cBAMi7w6VtbzOO3DS2cQwK6MIc4Fx1CZBabqUJELzRT6NXAo CRrKZA9y7DpXzhQzVQmmqYeey7Te5U4mM3IG6pA10wOTanoxSr8JcxCzsstDDZByhBl279RoR He0Hn2hdxwI6XAMZBeKnmTo72wPZC6I8mD0bvaiguN4Mb0VabbEXdG4zn8A68ZD' FACEBOOK_APP_ID =100007647638324 #Create a FaceBook Graph object facebook_graph = facebook.GraphAPI(access_token) #Posting Text only To Wall To attach a pic must be registered as a developer. facebook_graph.put_wall_post(message,profile_id='me') print "Facebook Wall Updated" ######################################################################### ########################################### # Twitter Function ######################################################################### ########################################### def Tweet(Text,temp,light): #set the localtime variable localtime = time.asctime( time.localtime(time.time())) #Set The message variable"msg" = The alert plus localTime, + temp and light msg = Text+(localtime)+"\nCurrent Conditions"+"\nTemp is =\t"+temp+"C"+"\nLight Level is =\t"+light+" lumina" #Twitter Access Keys CONSUMER_KEY = 'RbwVNyNI25q3U1y2TKhdw' CONSUMER_SECRET = '09dK2OkqVuVo9I12mUzltm01gi4YtnTXSZfvLwpA4' ACCESS_KEY = '2317027770-HgSg4Q4Xn4uzDpZwKpABUz67QxFVb8ah57LB51D' ACCESS_SECRET = 'a8FiPxgpbBif93qaUQpa3w5zaq0bq6KizUkvV8SDnJZZn' #Use Twython api To sign in to twitter api = Twython(CONSUMER_KEY,CONSUMER_SECRET,ACCESS_KEY,ACCESS_SECRET) #Open jpg image, "rb" is read only byte for photo = open('my_image.jpg', 'rb') try: #Update satus api.update_status_with_media(status=msg, media=photo) # error handling except TwythonError as e: print e ######################################################################### ########################################### # Text Message Service ######################################################################### ########################################### #Function text taking in text , temp and light variables def Text (Text,temp,light): #This was originaly ment to be an mms message service but mms is un avaiable in ireland from this service. #There is no Python api for txtlocal(webbased sms service) this is adapted from a pHp version #set the localtime variable localtime = time.asctime( time.localtime(time.time()) ) #Set The message variable"str = The alert plus Time message = Text+(localtime)+"\nCurrent Conditions"+"\nTemp is =\t"+temp+"C"+"\nLight Level is =\t"+light+" lumina" # Set username and sender name. # Sender name between 3 and 11 characters in length

Page 67 of 71

Evaluation of the Zero MQ socket library


username = "almat1981@gmail.com" sender = "Pi Project" # unique hash Gotten from textlocal Php program hash = "e373cafb7f4919f3b4f729781b2e7bb17e42cdc2" # Set the phone number you wish to send the # Multiple numbers seprated by comma numbers = ("353872924405") message to.

DT080B

# Set flag to 1 to simulate for testing # To send real message set this flag to 0 test_flag = 0 #PHP arrays are ordered mappings, so used a Python OrderedDict instead of a regular dict so that the order of insertion is preserved values = {"test" : test_flag, "uname" : username, "hash" : hash, "message" : message, "from" : sender, "selectednums" : numbers } #url texts are sent from url = "http://www.txtlocal.com/sendsmspost.php" #Convert a mapping object or a sequence of two-element tuples to a percent-encoded string, suitable to pass to urlopen() postdata = urllib.urlencode(values) #Open the URL url, which is the Request object Postdata. req = urllib2.Request(url, postdata) #Try to send print "Attempt to send SMS ..." try: #Open the URL response = urllib2.urlopen(req) response_url = response.geturl() if response_url==url: print "SMS sent!" except urllib2.URLError, e: print "Send failed!" print e.reason return ######################################################################### ########################################### # Email function ######################################################################### ########################################### #Pass the three variables into the email function def Email (Text,temp,light): #From Address Can be any address fromaddr = "alanspiproject2013@gmail.com" # Address To Must be a valid addresses tolist = "alanspiproject2013@gmail.com" # Message body text = Text+"\nCurrent Conditions"+"\nTemp is ="+temp+" Degrees C"+"\nLight Level is ="+light+" lumina" # Attachment location /path/to/file in this instance file is in same folder so name is sufficent filename = 'my_image.jpg' # Credentials username = "alanspiproject2013@gmail.com" password = "Al1981mat" #SMTP host address and port number

Page 68 of 71

Evaluation of the Zero MQ socket library

DT080B

host = 'smtp.gmail.com' port = 587 # Create a stmp object clled server server = smtplib.SMTP() #connect to smtp host server.connect( host,port) #start Transport Layer Security server.starttls() #Login to mail server server.login(username,password) #Sbject Field sub = ('Subject: Update From PI ') #Mimemultipart allows Multiple attachments Divides the message into parts, Each part has headers including the type of data, filename, encoding used msg = email.MIMEMultipart.MIMEMultipart() msg['From'] = fromaddr msg['To'] = toaddrs msg['Subject'] = sub msg.attach(MIMEText(text)) msg.attach(MIMEText('\nsent via python From PI Server', 'plain')) # 'plain ' is a plain text type #file import file as read only in bytewise process f = open(filename,'rb') #ctypy provides C compatible data types, and allows calling functions in DLLs or shared libraries. #load file and guess what it is. ctype, encoding = mimetypes.guess_type(filename) if ctype is None or encoding is not None: ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) if maintype == 'text': part = MIMEText(f.read(), _subtype=subtype) elif maintype == 'image': part = MIMEImage(f.read(), _subtype=subtype) elif maintype == 'audio': part = MIMEAudio(f.read(), _subtype=subtype) else: part = MIMEBase(maintype, subtype) msg.set_payload(f.read()) #attach the file part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(filename)) msg.attach(part) #close the file f.close() #send the mail server.sendmail(username,tolist,msg.as_string()) #Quit server server.quit() # code refrence http://docs.python.org/2/library/email-examples.html return ######################################################################### ########################################### # Main server program ######################################################################### ########################################### def Server(): #start of ZmQ Server or main program

Page 69 of 71

Evaluation of the Zero MQ socket library


#Create context object to a zmq Context context = zmq.Context() #Set socket contex to Rep, for a REQ-REP socket socket = context.socket(zmq.REP) #Bind Socket to "tcp://Localhost:Portnumber" socket.bind("tcp://192.168.2.5:5561") #loop ctrl-c while True: # Wait for next request from client message = socket.recv() #Split the recived message at: to seprate out the image , and variables from the string text, Image, light, temp = message.split(":") #Print variables to screen print "Received request: ", text print "The text is = ", text print "The Temp is = ", temp,"C" print "The Light is =", light," lumina" #uncomment below to see Image as a string #print "The Image is = ",Image #open image file in "wb" (writeable and binary mode). f = open("my_image.jpg", "wb") #Deccode back to an image from string using base64 f.write(Image.decode('base64')) # close file f.close() #IF Else srting of possiable requests if text == "Motion": #Pass variables to functions and set text to FaceBook("Motion Detected @",temp,light) Tweet("Motion Detected @ ",temp,light) Email("Motion Detected ",temp,light) Text("Motion Detected @",temp,light) time.sleep (1) #Send reply back to client socket.send("Detected") elif text == "Button": FaceBook("Button Pressed @",temp,light) Tweet("Button Pressed @",temp,light) Email("Button Pressed ",temp,light) Text("Button Pressed @",temp,light) time.sleep(1) socket.send("Pressed") #condition for low light elif text == "Dark": FaceBook("It's dark in Here @",temp,light) Tweet("It's dark in Here @",temp,light) Email("It's dark in Here",temp,light) Text("It's Dark in Here @",temp,light) time.sleep (1) # Send reply back to client socket.send("LightOn") #conditon for Cold elif text == "Cold": FaceBook("It's Cold In Here @",temp,light) Tweet("It's Cold In Here @",temp,light) Email("It's Cold In Here",temp,light) Text("It's Cold In Here @",temp,light)

DT080B

Page 70 of 71

Evaluation of the Zero MQ socket library


time.sleep (1) #Send reply back to client socket.send("HeatOn") #Condition for Hot elif text == "Hot": FaceBook("It's Getting Hot In Here @ ",temp,light) Tweet("It's Getting Hot In Here @ ",temp,light) Email("It's Getting Hot In Here",temp,light) Text("It's Getting Hot In Here @",temp,light) time.sleep (1) #Send reply back to client socket.send("FanOn") #Condition for timed satus update elif text == "Satus Update": FaceBook("Satus Update From Pi @",temp,light) Tweet("Satus Update From Pi @",temp,light) Email("Satus Update From Pi",temp,light) Text("Satus Update From Pi",temp,light) #Send reply back to client socket.send("Satus Recived") #If unknown mwssage reciver reply else: # Do some 'work' time.sleep (1) # Send reply back to client print("What'chu talkin' 'bout, Willis?") socket.send("What'chu talkin' 'bout, Willis?")

DT080B

######################################################################### ########################################### # Main Program ######################################################################### ########################################### def main(): #run till control c print "Hit control-c to Quit" try: Server() except KeyboardInterrupt: print "You hit control-c Goodbye" if __name__ == "__main__": main()

Page 71 of 71

You might also like