evaluation of the zero mq socket library
DESCRIPTION
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.TRANSCRIPT
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
Page 2 of 71
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 _______________________________________________________
Evaluation of the Zero MQ socket library DT080B
Page 3 of 71
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
Evaluation of the Zero MQ socket library DT080B
Page 4 of 71
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.
Evaluation of the Zero MQ socket library DT080B
Page 5 of 71
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.
Evaluation of the Zero MQ socket library DT080B
Page 6 of 71
For example, if the light level drops below a certain level, the system will “Publish” the
message “it’s dark”, on the server side. When the message “it’s 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.
Evaluation of the Zero MQ socket library DT080B
Page 7 of 71
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 message-
oriented. 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" .
Evaluation of the Zero MQ socket library DT080B
Page 8 of 71
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.
Evaluation of the Zero MQ socket library DT080B
Page 9 of 71
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.
Evaluation of the Zero MQ socket library DT080B
Page 10 of 71
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).
Evaluation of the Zero MQ socket library DT080B
Page 11 of 71
ZMQ_REQ Socket:
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 ZMQ_REP
Direction Bidirectional
Send/receive pattern Send, Receive, Send, Receive, …
Outgoing routing strategy Round-robin
Incoming routing strategy Last peer
ZMQ_HWM option action Block
( iMatix Corporation, 2012)
Evaluation of the Zero MQ socket library DT080B
Page 12 of 71
ZMQ_REP Socket:
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 ZMQ_REQ
Direction Bidirectional
Send/receive pattern Receive, Send, Receive,
Send, …
Incoming routing strategy Fair-queued
Outgoing routing strategy Last peer
ZMQ_HWM option action Drop
(iMatix Corporation, 2012)
Evaluation of the Zero MQ socket library DT080B
Page 13 of 71
ZMQ_PUB socket:
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 ZMQ_SUB
Direction Unidirectional
Send/receive pattern Send only
Incoming routing strategy N/A
Outgoing routing strategy Fan out
ZMQ_HWM option action Drop
(iMatix Corporation, 2012)
Evaluation of the Zero MQ socket library DT080B
Page 14 of 71
ZMQ_SUB socket:
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 ZMQ_PUB
Direction Unidirectional
Send/receive pattern Receive only
Incoming routing strategy Fair-queued
Outgoing routing strategy N/A
ZMQ_HWM option action Drop
( iMatix Corporation, 2012)
Evaluation of the Zero MQ socket library DT080B
Page 15 of 71
ZMQ_PUSH
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 ZMQ_PULL
Direction Unidirectional
Send/receive pattern Send only
Incoming routing strategy N/A
Outgoing routing strategy Round-robin
ZMQ_HWM option action Block
(iMatix Corporation, 2012)
Evaluation of the Zero MQ socket library DT080B
Page 16 of 71
ZMQ_PULL
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 ZMQ_PUSH
Direction Unidirectional
Send/receive pattern Receive only
Incoming routing strategy Fair-queued
Outgoing routing strategy N/A
ZMQ_HWM option action N/A
( iMatix Corporation, 2012)
Evaluation of the Zero MQ socket library DT080B
Page 17 of 71
ZMQ_DEALER
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 ZMQ_ROUTER, ZMQ_REQ, ZMQ_REP
Direction Bidirectional
Send/receive pattern Unrestricted
Outgoing routing strategy Round-robin
Incoming routing strategy Fair-queued
ZMQ_HWM option action Block
( iMatix Corporation, 2012)
Evaluation of the Zero MQ socket library DT080B
Page 18 of 71
ZMQ_ROUTER
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 Bidirectional
Send/receive pattern Unrestricted
Outgoing routing strategy See text
Incoming routing strategy Fair-queued
ZMQ_HWM option action Drop
Evaluation of the Zero MQ socket library DT080B
Page 19 of 71
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.
Evaluation of the Zero MQ socket library DT080B
Page 20 of 71
Figure 2 REP-REQ Pattern Client Python Code
# 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))
Evaluation of the Zero MQ socket library DT080B
Page 21 of 71
2. Publish/Subscribe Pattern
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.
Evaluation of the Zero MQ socket library DT080B
Page 22 of 71
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()
Evaluation of the Zero MQ socket library DT080B
Page 23 of 71
3. Pipeline Pattern
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
Evaluation of the Zero MQ socket library DT080B
Page 24 of 71
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.
Evaluation of the Zero MQ socket library DT080B
Page 25 of 71
Figure 8 Ventilator Code Python Example
# 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)
Evaluation of the Zero MQ socket library DT080B
Page 26 of 71
Figure 9 Worker Code In Python
# 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)
Evaluation of the Zero MQ socket library DT080B
Page 27 of 71
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)
Evaluation of the Zero MQ socket library DT080B
Page 28 of 71
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!
Evaluation of the Zero MQ socket library DT080B
Page 29 of 71
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.
Evaluation of the Zero MQ socket library DT080B
Page 30 of 71
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()
Evaluation of the Zero MQ socket library DT080B
Page 31 of 71
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
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")
Evaluation of the Zero MQ socket library DT080B
Page 32 of 71
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 read-
only 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 function:
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
Evaluation of the Zero MQ socket library DT080B
Page 33 of 71
Figure 18 Tweet Results
Evaluation of the Zero MQ socket library DT080B
Page 34 of 71
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 digital-
only 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 (SS 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.
Evaluation of the Zero MQ socket library DT080B
Page 35 of 71
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
Evaluation of the Zero MQ socket library DT080B
Page 36 of 71
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
doesn’t require bit-banging. However, as it’s 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
Evaluation of the Zero MQ socket library DT080B
Page 37 of 71
sampled on any of the ADC’s 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]
Evaluation of the Zero MQ socket library DT080B
Page 38 of 71
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
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
Evaluation of the Zero MQ socket library DT080B
Page 39 of 71
time.sleep(0.01)
Evaluation of the Zero MQ socket library DT080B
Page 40 of 71
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
Evaluation of the Zero MQ socket library DT080B
Page 41 of 71
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)
Evaluation of the Zero MQ socket library DT080B
Page 42 of 71
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()
Figure 29 Results of Camera and analogue sensor addition
Evaluation of the Zero MQ socket library DT080B
Page 43 of 71
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
Evaluation of the Zero MQ socket library DT080B
Page 44 of 71
Figure 31 Push button results
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)
Evaluation of the Zero MQ socket library DT080B
Page 45 of 71
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")
Evaluation of the Zero MQ socket library DT080B
Page 46 of 71
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"
Evaluation of the Zero MQ socket library DT080B
Page 47 of 71
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)"
Evaluation of the Zero MQ socket library DT080B
Page 48 of 71
#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)
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"
Evaluation of the Zero MQ socket library DT080B
Page 49 of 71
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 = "[email protected]"
# Address To Must be a valid addresses
tolist = "[email protected]"
# 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 = "[email protected]"
password = "Al1981mat"
#SMTP host address and port number
host = 'smtp.gmail.com'
port = 587
# Create a stmp object clled server
Evaluation of the Zero MQ socket library DT080B
Page 50 of 71
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
Evaluation of the Zero MQ socket library DT080B
Page 51 of 71
Figure 39 Email Results:
Evaluation of the Zero MQ socket library DT080B
Page 52 of 71
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.
Evaluation of the Zero MQ socket library DT080B
Page 53 of 71
Figure 40 Text Function Code
#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 = "[email protected]"
sender = "Pi Project"
# unique hash Gotten from textlocal Php program
hash = "e373cafb7f4919f3b4f729781b2e7bb17e42cdc2"
# Set the phone number you wish to send the message to.
# Multiple numbers separated by comma
numbers = ("353872924405")
# 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
Evaluation of the Zero MQ socket library DT080B
Page 54 of 71
Evaluation of the Zero MQ socket library DT080B
Page 55 of 71
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
Evaluation of the Zero MQ socket library DT080B
Page 56 of 71
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 API’s 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.
Evaluation of the Zero MQ socket library DT080B
Page 57 of 71
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.
Evaluation of the Zero MQ socket library DT080B
Page 58 of 71
Bibliography
iMatix Corporation, 2012. ØMQ API Reference. [Online]
Available at: http://api.zeromq.org/
[Accessed 7 03 2014].
Al-Hertani., H., 2013. http://hertaville.com/. [Online]
Available at: 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., n.d. [Online]
Available at: http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-
Peripherals.pdf
Grigorik, I., 2010. http://www.igvita.com/. [Online]
Available at: http://www.igvita.com/2010/09/03/zeromq-modern-fast-networking-stack/
[Accessed 21 01 2014].
halherta, July 24, 2013 . http://hertaville.com/. [Online]
Available at: 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, D. K. a. R., 2002. embedded.com. [Online]
Available at: 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
Evaluation of the Zero MQ socket library DT080B
Page 59 of 71
Scherfke, S., 2012. Designing and Testing PyZMQ Applications, Oldenburg, Germany:
OFFIS – Institute for Information Technology Oldenburg, Germany.
Tezer, O., n.d. [Online]
Available at: 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
Evaluation of the Zero MQ socket library DT080B
Page 60 of 71
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
Evaluation of the Zero MQ socket library DT080B
Page 61 of 71
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
Evaluation of the Zero MQ socket library DT080B
Page 62 of 71
# 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) 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
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)
Evaluation of the Zero MQ socket library DT080B
Page 63 of 71
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)
Evaluation of the Zero MQ socket library DT080B
Page 64 of 71
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
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
Evaluation of the Zero MQ socket library DT080B
Page 65 of 71
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 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
#########################################################################
###########################################
Evaluation of the Zero MQ socket library DT080B
Page 66 of 71
#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
Evaluation of the Zero MQ socket library DT080B
Page 67 of 71
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
Evaluation of the Zero MQ socket library DT080B
Page 68 of 71
username = "[email protected]"
sender = "Pi Project"
# unique hash Gotten from textlocal Php program
hash = "e373cafb7f4919f3b4f729781b2e7bb17e42cdc2"
# Set the phone number you wish to send the message to.
# Multiple numbers seprated by comma
numbers = ("353872924405")
# 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 = "[email protected]"
# Address To Must be a valid addresses
tolist = "[email protected]"
# 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 = "[email protected]"
password = "Al1981mat"
#SMTP host address and port number
Evaluation of the Zero MQ socket library DT080B
Page 69 of 71
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
Evaluation of the Zero MQ socket library DT080B
Page 70 of 71
#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)
Evaluation of the Zero MQ socket library DT080B
Page 71 of 71
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?")
#########################################################################
###########################################
# 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()