The Problem |
What they don't say - or don't say loud enough - is that to do so, your web server needs to be visible to (and from) the outside world.
Otherwise, you cannot access it outside of your home or ad-hoc network.
What those articles present is a nice way to:
- Know what the conditions are on the Raspberry PI
- Ask remotely to the Raspberry PI to take some action
- For example
-
You are at work, the Raspberry PI is at home.
Your Raspberry PI has a temperature sensor connected to it, and it is also connected to some heater switch.- When the temperature in the home drops below a given threshold, it sends you a message (through whatever channel, WebSocket or so)
- On reception of the message, you - wherever you are - decide to ask the Raspberry PI to turn the heater on
It kind of kills the story...
A Solution |
This will not implement real-time messaging - like WebSocket - but this will allow a form of communication, only relying on email service - like Yahoo! or Google. Those providers offer free email accounts, which is all you would need.
Required Components |
On the server side (ie the Raspberry PI, at home) you will need: The json parser is used to parse the content of the email messages. We choosed this technology in this example; others can be used as well, like XML, plain text messages, etc. Your call.
The Java code |
- email.properties
-
All properties concerning the emails accounts are externalized in this properties file.
Lines 1 to 5 concern the origins, and the destinations of the emails going back and forth, as well as the subjects used for the emails (events, acknowledgements, and requests).
Notice the URL at the top of the file (line 7), it could help you to find the servers you are interested in.
1 pi.accept.emails.from=olivier.lediouris@gmail.com, olivier.lediouris@yahoo.com, olivier@lediouris.net 2 pi.send.emails.to=olivier.lediouris@gmail.com, olivier.lediouris@yahoo.com, olivier@lediouris.net 3 pi.email.subject=PI Request 4 pi.ack.subject=PI Robot Ack 5 pi.event.subject=PI Event 6 # 7 # See http://www.arclab.com/products/amlc/list-of-smtp-and-pop3-servers-mailserver-list.html 8 # 9 pi.yahoo.mail.protocol=pop3 10 pi.yahoo.incoming.server=pop.mail.yahoo.com 11 pi.yahoo.outgoing.server=smtp.mail.yahoo.com 12 pi.yahoo.mail.smtpauth=true 13 pi.yahoo.outgoing.server.port=587 14 pi.yahoo.mail.username=olivier.lediouris 15 pi.yahoo.mail.password=XXXXXX 16 pi.yahoo.mail.replyto=olivier@lediouris.net 17 # 18 pi.google.mail.protocol=pop3 19 pi.google.incoming.server=pop.gmail.com 20 pi.google.outgoing.server=smtp.gmail.com 21 pi.google.mail.smtpauth=true 22 pi.google.outgoing.server.port=465 23 pi.google.incoming.server.port=995 24 pi.google.mail.username=olivier.lediouris@gmail.com 25 pi.google.mail.password=XXXXXX 26 pi.google.mail.replyto=olivier.lediouris@gmail.com 27 # 28 pi.oracle.mail.protocol=imap 29 pi.oracle.incoming.server=stbeehive.oracle.com 30 pi.oracle.outgoing.server=stbeehive.oracle.com 31 pi.oracle.mail.smtpauth=true 32 pi.oracle.outgoing.server.port=465 33 pi.oracle.incoming.server.port=993 34 pi.oracle.mail.username=olivier.lediouris@oracle.com 35 pi.oracle.mail.password=XXXXXX 36 pi.oracle.mail.replyto=olivier.lediouris@oracle.com 37 #
- pi4j.gpio.RaspberryPIEventListener.java
- This is the interface used for the callback invoked when an event is triggered on the Reaspberry Pi's side. Namely, when the button will be pressed.
1 package pi4j.gpio;
2
3 import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
4
5 public interface RaspberryPIEventListener
6 {
7 public void manageEvent(GpioPinDigitalStateChangeEvent event);
8 }
- pi4j.email.EmailReceiver.java
-
This is the utility class used to receive emails. Its behavior heavily depends on the values
set in
email.properties.
Do check out the method namedsetProps()(line 119). It might need to be tweaked to fit your email environment.
1 package pi4j.email;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.io.FileOutputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.InputStreamReader;
10 import java.io.OutputStream;
11
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.Properties;
15 import java.util.Set;
16
17 import javax.mail.Address;
18 import javax.mail.Flags;
19 import javax.mail.Folder;
20 import javax.mail.Message;
21 import javax.mail.Multipart;
22 import javax.mail.Part;
23 import javax.mail.PasswordAuthentication;
24 import javax.mail.Session;
25 import javax.mail.Store;
26 import javax.mail.internet.InternetAddress;
27 import javax.mail.search.AndTerm;
28 import javax.mail.search.FlagTerm;
29 import javax.mail.search.FromStringTerm;
30 import javax.mail.search.OrTerm;
31 import javax.mail.search.SearchTerm;
32 import javax.mail.search.SubjectTerm;
33
34 public class EmailReceiver
35 {
36 private static String protocol;
37 private static int outgoingPort;
38 private static int incomingPort;
39 private static String username;
40 private static String password;
41 private static String outgoing;
42 private static String incoming;
43 private static String replyto;
44 private static boolean smtpauth;
45
46 private static String sendEmailsTo;
47 private static String acceptEmailsFrom;
48 private static String acceptSubject;
49 private static String ackSubject;
50
51 private static boolean verbose = "true".equals(System.getProperty("verbose", "false"));
52
53 private EmailSender emailSender = null; // For Ack
54 private String provider = null;
55
56 public EmailReceiver(String provider) throws RuntimeException
57 {
58 this.provider = provider;
59 EmailReceiver.protocol = "";
60 EmailReceiver.outgoingPort = 0;
61 EmailReceiver.incomingPort = 0;
62 EmailReceiver.username = "";
63 EmailReceiver.password = "";
64 EmailReceiver.outgoing = "";
65 EmailReceiver.incoming = "";
66 EmailReceiver.replyto = "";
67 EmailReceiver.smtpauth = false;
68
69 EmailReceiver.sendEmailsTo = "";
70 EmailReceiver.acceptEmailsFrom = "";
71 EmailReceiver.acceptSubject = "";
72 EmailReceiver.ackSubject = "";
73
74 Properties props = new Properties();
75 String propFile = "email.properties";
76 try
77 {
78 FileInputStream fis = new FileInputStream(propFile);
79 props.load(fis);
80 }
81 catch (Exception e)
82 {
83 System.out.println("email.properies file problem...");
84 throw new RuntimeException("File not found:email.properies");
85 }
86 EmailReceiver.sendEmailsTo = props.getProperty("pi.send.emails.to");
87 EmailReceiver.acceptEmailsFrom = props.getProperty("pi.accept.emails.from");
88 EmailReceiver.acceptSubject = props.getProperty("pi.email.subject");
89 EmailReceiver.ackSubject = props.getProperty("pi.ack.subject");
90
91 EmailReceiver.protocol = props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "mail.protocol");
92 EmailReceiver.outgoingPort = Integer.parseInt(props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "outgoing.server.port", "0"));
93 EmailReceiver.incomingPort = Integer.parseInt(props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "incoming.server.port", "0"));
94 EmailReceiver.username = props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "mail.username", "");
95 EmailReceiver.password = props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "mail.password", "");
96 EmailReceiver.outgoing = props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "outgoing.server", "");
97 EmailReceiver.incoming = props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "incoming.server", "");
98 EmailReceiver.replyto = props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "mail.replyto", "");
99 EmailReceiver.smtpauth = "true".equals(props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "mail.smtpauth", "false"));
100
101 if (verbose)
102 {
103 System.out.println("Protocol:" + EmailReceiver.protocol);
104 System.out.println("Usr/pswd:" + EmailReceiver.username + "/" + EmailReceiver.password);
105 }
106 }
107
108 private static SearchTerm[] buildSearchTerm(String str)
109 {
110 String[] sa = str.split(",");
111 List<SearchTerm> lst = new ArrayList<SearchTerm>();
112 for (String s : sa)
113 lst.add(new FromStringTerm(s.trim()));
114 SearchTerm[] sta = new SearchTerm[lst.size()];
115 sta = lst.toArray(sta);
116 return sta;
117 }
118
119 private Properties setProps()
120 {
121 Properties props = new Properties();
122 props.put("mail.debug", verbose?"true":"false");
123
124 // TASK smtp should be irrelevant for a receiver
125 props.put("mail.smtp.host", EmailReceiver.outgoing);
126 props.put("mail.smtp.port", Integer.toString(EmailReceiver.outgoingPort));
127
128 props.put("mail.smtp.auth", "true");
129 props.put("mail.smtp.starttls.enable", "true"); // See http://www.oracle.com/technetwork/java/faq-135477.html#yahoomail
130 // props.put("mail.smtp.starttls.required", "true");
131 props.put("mail.smtp.ssl.enable", "true");
132
133 if ("pop3".equals(EmailReceiver.protocol))
134 {
135 props.setProperty("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
136 props.setProperty("mail.pop3.socketFactory.fallback", "false");
137 props.setProperty("mail.pop3.port", Integer.toString(EmailReceiver.incomingPort));
138 props.setProperty("mail.pop3.socketFactory.port", Integer.toString(EmailReceiver.incomingPort));
139 }
140
141 if ("imap".equals(protocol))
142 {
143 props.setProperty("mail.imap.starttls.enable", "false");
144 // Use SSL
145 props.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
146 props.setProperty("mail.imap.socketFactory.fallback", "false");
147
148 props.setProperty("mail.imap.port", Integer.toString(EmailReceiver.incomingPort));
149 props.setProperty("mail.imap.socketFactory.port", Integer.toString(EmailReceiver.incomingPort));
150
151 props.setProperty("mail.imaps.class", "com.sun.mail.imap.IMAPSSLStore");
152 }
153 return props;
154 }
155
156 public boolean isAuthRequired()
157 {
158 return EmailReceiver.smtpauth;
159 }
160
161 public String getUserName()
162 {
163 return EmailReceiver.username;
164 }
165
166 public String getPassword()
167 {
168 return EmailReceiver.password;
169 }
170
171 public String getReplyTo()
172 {
173 return EmailReceiver.replyto;
174 }
175
176 public String getIncomingServer()
177 {
178 return EmailReceiver.incoming;
179 }
180
181 public String getOutgoingServer()
182 {
183 return EmailReceiver.outgoing;
184 }
185
186 public List<String> receive()
187 throws Exception
188 {
189 return receive(null);
190 }
191
192 public List<String> receive(String dir)
193 throws Exception
194 {
195 if (verbose) System.out.println("Receiving...");
196 List<String> messList = new ArrayList<String>();
197 Store store = null;
198 Folder folder = null;
199 try
200 {
201 // Properties props = System.getProperties();
202 Properties props = setProps();
203
204 if (verbose)
205 {
206 Set<Object> keys = props.keySet();
207 for (Object o : keys)
208 System.out.println(o.toString() + ":" + props.get(o).toString());
209 }
210 if (verbose) System.out.println("Getting session...");
211 // Session session = Session.getInstance(props, null);
212 Session session = Session.getInstance(props,
213 new javax.mail.Authenticator()
214 {
215 protected PasswordAuthentication getPasswordAuthentication()
216 {
217 return new PasswordAuthentication(username, password);
218 }
219 });
220 session.setDebug(verbose);
221 if (verbose) System.out.println("Session established.");
222 store = session.getStore(EmailReceiver.protocol);
223 if (EmailReceiver.incomingPort == 0)
224 store.connect(EmailReceiver.incoming, EmailReceiver.username, EmailReceiver.password);
225 else
226 store.connect(EmailReceiver.incoming, EmailReceiver.incomingPort, EmailReceiver.username, EmailReceiver.password);
227 if (verbose) System.out.println("Connected to store");
228 folder = store.getDefaultFolder();
229 if (folder == null)
230 throw new RuntimeException("No default folder");
231
232 folder = store.getFolder("INBOX");
233 if (folder == null)
234 throw new RuntimeException("No INBOX");
235
236 folder.open(Folder.READ_WRITE);
237 if (verbose) System.out.println("Connected... filtering, please wait.");
238 SearchTerm st = new AndTerm(new SearchTerm[] { new OrTerm(buildSearchTerm(sendEmailsTo)),
239 new SubjectTerm(acceptSubject),
240 new FlagTerm(new Flags(Flags.Flag.SEEN), false) });
241 // st = new SubjectTerm("PI Request");
242 Message msgs[] = folder.search(st);
243 // Message msgs[] = folder.getMessages();
244
245 if (verbose) System.out.println("Search completed, " + msgs.length + " message(s).");
246 for (int msgNum=0; msgNum<msgs.length; msgNum++)
247 {
248 try
249 {
250 Message mess = msgs[msgNum];
251 Address from[] = mess.getFrom();
252 String sender = "";
253 try
254 {
255 sender = from[0].toString();
256 }
257 catch(Exception exception)
258 {
259 exception.printStackTrace();
260 }
261 // System.out.println("Message from [" + sender + "], subject [" + subject + "], content [" + mess.getContent().toString().trim() + "]");
262
263 if (true)
264 {
265 if (!mess.isSet(javax.mail.Flags.Flag.SEEN) &&
266 !mess.isSet(javax.mail.Flags.Flag.DELETED))
267 {
268 String txtMess = printMessage(mess, dir);
269 messList.add(txtMess);
270 mess.setFlag(javax.mail.Flags.Flag.SEEN, true);
271 mess.setFlag(javax.mail.Flags.Flag.DELETED, true);
272 // Send an ack - by email.
273 if (this.emailSender == null)
274 this.emailSender = new EmailSender(this.provider);
275 this.emailSender.send(new String[] { sender },
276 ackSubject,
277 "Your request [" + txtMess.trim() + "] is being taken care of.");
278 if (verbose) System.out.println("Sent an ack to " + sender);
279 }
280 else
281 {
282 if (verbose) System.out.println("Old message in your inbox..., received " + mess.getReceivedDate().toString());
283 }
284 }
285 }
286 catch(Exception ex)
287 {
288 // System.err.println(ex.getMessage());
289 ex.printStackTrace();
290 }
291 }
292 }
293 catch(Exception ex)
294 {
295 throw ex;
296 }
297 finally
298 {
299 try
300 {
301 if (folder != null)
302 folder.close(true);
303 if (store != null)
304 store.close();
305 }
306 catch(Exception ex2)
307 {
308 System.err.println("Finally ...");
309 ex2.printStackTrace();
310 }
311 }
312 return messList;
313 }
314
315 public static String printMessage(Message message, String dir)
316 {
317 String ret = "";
318 try
319 {
320 String from = ((InternetAddress)message.getFrom()[0]).getPersonal();
321 if(from == null)
322 from = ((InternetAddress)message.getFrom()[0]).getAddress();
323 if (verbose) System.out.println("From: " + from);
324 String subject = message.getSubject();
325 if (verbose) System.out.println("Subject: " + subject);
326 Part messagePart = message;
327 Object content = messagePart.getContent();
328 if (content instanceof Multipart)
329 {
330 // messagePart = ((Multipart)content).getBodyPart(0);
331 int nbParts = ((Multipart)content).getCount();
332 if (verbose) System.out.println("[ Multipart Message ], " + nbParts + " part(s).");
333 for (int i=0; i<nbParts; i++)
334 {
335 messagePart = ((Multipart)content).getBodyPart(i);
336 if (messagePart.getContentType().toUpperCase().startsWith("APPLICATION/OCTET-STREAM"))
337 {
338 if (verbose) System.out.println(messagePart.getContentType() + ":" + messagePart.getFileName());
339 InputStream is = messagePart.getInputStream();
340 String newFileName = "";
341 if (dir != null)
342 newFileName = dir + File.separator;
343 newFileName += messagePart.getFileName();
344 FileOutputStream fos = new FileOutputStream(newFileName);
345 ret = messagePart.getFileName();
346 if (verbose) System.out.println("Downloading " + messagePart.getFileName() + "...");
347 copy(is, fos);
348 if (verbose) System.out.println("...done.");
349 }
350 else // text/plain, text/html
351 {
352 if (verbose) System.out.println("-- Part #" + i + " --, " + messagePart.getContentType().replace('\n', ' ').replace('\r', ' ').replace("\b", "").trim());
353 InputStream is = messagePart.getInputStream();
354 BufferedReader br = new BufferedReader(new InputStreamReader(is));
355 String line = "";
356 while (line != null)
357 {
358 line = br.readLine();
359 if (line != null)
360 {
361 if (verbose) System.out.println("[" + line + "]");
362 if (messagePart.getContentType().toUpperCase().startsWith("TEXT/PLAIN"))
363 ret += line;
364 }
365 }
366 br.close();
367 if (verbose) System.out.println("-------------------");
368 }
369 }
370 }
371 else
372 {
373 // System.out.println(" .Message is a " + content.getClass().getName());
374 // System.out.println("Content:");
375 // System.out.println(content.toString());
376 ret = content.toString();
377 }
378 if (verbose) System.out.println("-----------------------------");
379 }
380 catch(Exception ex)
381 {
382 ex.printStackTrace();
383 }
384 return ret;
385 }
386
387 private static void copy(InputStream in, OutputStream out)
388 throws IOException
389 {
390 synchronized(in)
391 {
392 synchronized(out)
393 {
394 byte buffer[] = new byte[256];
395 while (true)
396 {
397 int bytesRead = in.read(buffer);
398 if(bytesRead == -1)
399 break;
400 out.write(buffer, 0, bytesRead);
401 }
402 }
403 }
404 }
405 }
- pi4j.email.EmailSender.java
-
Same as the previous, but for outgoing emails. Notice that the two can be different.
You might very well send emails using Yahoo! and receive others using Google.
This way, the Raspberry PI and you would have your own email addresses.
As before, check out the method namedsetProps()(line 164). It might need to be tweaked to fit your email environment.
1 package pi4j.email;
2
3 import com.sun.mail.smtp.SMTPTransport;
4
5 import java.io.FileInputStream;
6
7 import java.util.Properties;
8
9 import javax.mail.Message;
10 import javax.mail.MessagingException;
11 import javax.mail.PasswordAuthentication;
12 import javax.mail.Session;
13 import javax.mail.Transport;
14 import javax.mail.internet.AddressException;
15 import javax.mail.internet.InternetAddress;
16 import javax.mail.internet.MimeMessage;
17
18 public class EmailSender
19 {
20 private static String protocol;
21 private static int outgoingPort;
22 private static int incomingPort;
23 private static String username;
24 private static String password;
25 private static String outgoing;
26 private static String incoming;
27 private static String replyto;
28 private static boolean smtpauth;
29
30 private static String sendEmailsTo;
31 private static String eventSubject;
32
33 private static boolean verbose = "true".equals(System.getProperty("verbose", "false"));
34
35 public EmailSender(String provider) throws RuntimeException
36 {
37 EmailSender.protocol = "";
38 EmailSender.outgoingPort = 0;
39 EmailSender.incomingPort = 0;
40 EmailSender.username = "";
41 EmailSender.password = "";
42 EmailSender.outgoing = "";
43 EmailSender.incoming = "";
44 EmailSender.replyto = "";
45 EmailSender.smtpauth = false;
46 EmailSender.sendEmailsTo = "";
47 EmailSender.eventSubject = "";
48
49 Properties props = new Properties();
50 String propFile = "email.properties";
51 try
52 {
53 FileInputStream fis = new FileInputStream(propFile);
54 props.load(fis);
55 }
56 catch (Exception e)
57 {
58 System.out.println("email.properies file problem...");
59 throw new RuntimeException("File not found:email.properies");
60 }
61 EmailSender.sendEmailsTo = props.getProperty("pi.send.emails.to");
62 EmailSender.eventSubject = props.getProperty("pi.event.subject");
63
64 EmailSender.protocol = props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "mail.protocol");
65 EmailSender.outgoingPort = Integer.parseInt(props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "outgoing.server.port", "0"));
66 EmailSender.incomingPort = Integer.parseInt(props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "incoming.server.port", "0"));
67 EmailSender.username = props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "mail.username", "");
68 EmailSender.password = props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "mail.password", "");
69 EmailSender.outgoing = props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "outgoing.server", "");
70 EmailSender.incoming = props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "incoming.server", "");
71 EmailSender.replyto = props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "mail.replyto", "");
72 EmailSender.smtpauth = "true".equals(props.getProperty("pi." + (provider != null ? (provider + ".") : "") + "mail.smtpauth", "false"));
73
74 if (verbose)
75 {
76 System.out.println("-------------------------------------");
77 System.out.println("Protocol : " + EmailSender.protocol);
78 System.out.println("Usr/pswd : " + EmailSender.username + "/" + EmailSender.password);
79 System.out.println("Incoming server: " + EmailSender.incoming + ":" + EmailSender.incomingPort);
80 System.out.println("Outgoing server: " + EmailSender.outgoing + ":" + EmailSender.outgoingPort);
81 System.out.println("replyto : " + EmailSender.replyto);
82 System.out.println("SMTPAuth : " + EmailSender.smtpauth);
83 System.out.println("-------------------------------------");
84 }
85 }
86
87 public boolean isAuthRequired()
88 {
89 return EmailSender.smtpauth;
90 }
91
92 public String getUserName()
93 {
94 return EmailSender.username;
95 }
96
97 public String getPassword()
98 {
99 return EmailSender.password;
100 }
101
102 public String getReplyTo()
103 {
104 return EmailSender.replyto;
105 }
106
107 public String getIncomingServer()
108 {
109 return EmailSender.incoming;
110 }
111
112 public String getOutgoingServer()
113 {
114 return EmailSender.outgoing;
115 }
116
117 public String getEmailDest()
118 {
119 return EmailSender.sendEmailsTo;
120 }
121
122 public String getEventSubject()
123 {
124 return EmailSender.eventSubject;
125 }
126
127 public void send(String[] dest,
128 String subject,
129 String content)
130 throws MessagingException, AddressException
131 {
132 Properties props = setProps();
133
134 // Session session = Session.getDefaultInstance(props, auth);
135 Session session = Session.getInstance(props,
136 new javax.mail.Authenticator()
137 {
138 protected PasswordAuthentication getPasswordAuthentication()
139 {
140 return new PasswordAuthentication(username, password);
141 }
142 });
143 session.setDebug(verbose);
144 Transport tr = session.getTransport("smtp");
145 if (!(tr instanceof SMTPTransport))
146 System.out.println("This is NOT an SMTPTransport:[" + tr.getClass().getName() + "]");
147
148 Message msg = new MimeMessage(session);
149 msg.setFrom(new InternetAddress(EmailSender.replyto));
150 if (dest == null || dest.length == 0)
151 throw new RuntimeException("Need at least one recipient.");
152 msg.setRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(dest[0]));
153 for (int i=1; i<dest.length; i++)
154 msg.addRecipient(javax.mail.Message.RecipientType.CC, new InternetAddress(dest[i]));
155 msg.setSubject(subject);
156 msg.setText(content != null ? content : "");
157 msg.setContent(content, "text/plain");
158 msg.saveChanges();
159 if (verbose) System.out.println("sending:[" + content + "], " + Integer.toString(content.length()) + " characters");
160
161 Transport.send(msg);
162 }
163
164 private Properties setProps()
165 {
166 Properties props = new Properties();
167 props.put("mail.debug", verbose?"true":"false");
168 props.put("mail.smtp.host", EmailSender.outgoing);
169 props.put("mail.smtp.port", Integer.toString(EmailSender.outgoingPort));
170
171 props.put("mail.smtp.auth", "true");
172 props.put("mail.smtp.starttls.enable", "true"); // See http://www.oracle.com/technetwork/java/faq-135477.html#yahoomail
173 // props.put("mail.smtp.starttls.required", "true");
174 props.put("mail.smtp.ssl.enable", "true");
175 return props;
176 }
177 }
- pi4j.gpio.GPIOController.java
-
Interaction with the GPIO on the Raspberry PI.
Notice the pins we use:- Yellow led on pin #01 (line 23)
- Green led on pin #04 (line 24)
- Button on pin #02 (line 25)
1 package pi4j.gpio;
2
3 import com.pi4j.io.gpio.GpioController;
4 import com.pi4j.io.gpio.GpioFactory;
5 import com.pi4j.io.gpio.GpioPinDigitalInput;
6 import com.pi4j.io.gpio.PinPullResistance;
7 import com.pi4j.io.gpio.RaspiPin;
8 import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
9 import com.pi4j.io.gpio.event.GpioPinListenerDigital;
10
11 public class GPIOController
12 {
13 private GpioController gpio = null;
14 private OneLed yellowLed = null;
15 private OneLed greenLed = null;
16 private GpioPinDigitalInput button = null;
17 private RaspberryPIEventListener caller = null;
18
19 public GPIOController(RaspberryPIEventListener listener)
20 {
21 this.caller = listener;
22 this.gpio = GpioFactory.getInstance();
23 this.yellowLed = new OneLed(this.gpio, RaspiPin.GPIO_01, "yellow");
24 this.greenLed = new OneLed(this.gpio, RaspiPin.GPIO_04, "green");
25 this.button = this.gpio.provisionDigitalInputPin(RaspiPin.GPIO_02, PinPullResistance.PULL_DOWN);
26 this.button.addListener(new GpioPinListenerDigital()
27 {
28 @Override
29 public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event)
30 {
31 caller.manageEvent(event);
32 }
33 });
34 }
35
36 public void shutdown()
37 {
38 this.gpio.shutdown();
39 }
40
41 public void switchYellow(boolean on)
42 {
43 if (on)
44 yellowLed.on();
45 else
46 yellowLed.off();
47 }
48
49 public void switchGreen(boolean on)
50 {
51 if (on)
52 greenLed.on();
53 else
54 greenLed.off();
55 }
56 }
- pi4j.gpio.OneLed.java
- Utility class for led management.
1 package pi4j.gpio;
2
3
4 import com.pi4j.io.gpio.GpioController;
5 import com.pi4j.io.gpio.GpioPinDigitalOutput;
6 import com.pi4j.io.gpio.Pin;
7 import com.pi4j.io.gpio.PinState;
8
9 public class OneLed
10 {
11 private GpioPinDigitalOutput led = null;
12 private String name;
13
14 public OneLed(GpioController gpio, Pin pin, String name)
15 {
16 this.name = name;
17 led = gpio.provisionDigitalOutputPin(pin, "Led", PinState.LOW);
18 }
19
20 public void on()
21 {
22 if ("true".equals(System.getProperty("verbose", "false")))
23 System.out.println(this.name + " is on.");
24 led.high();
25 }
26
27 public void off()
28 {
29 if ("true".equals(System.getProperty("verbose", "false")))
30 System.out.println(this.name + " is off.");
31 led.low();
32 }
33 }
- pi4j.email.PIControllerMain.java
- This is the main, the one to start from the Raspberry PI (see below)
1 package pi4j.email;
2
3 import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
4
5 import java.text.SimpleDateFormat;
6
7 import java.util.Date;
8 import java.util.List;
9
10 import org.json.JSONObject;
11
12 import pi4j.gpio.GPIOController;
13 import pi4j.gpio.RaspberryPIEventListener;
14
15 public class PIControllerMain implements RaspberryPIEventListener
16 {
17 private final static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
18 private static boolean verbose = "true".equals(System.getProperty("verbose", "false"));
19
20 private static String providerSend = "google";
21 private static String providerReceive = "google";
22
23 EmailSender sender = null;
24
25 /**
26 * Invoked like:
27 * java pi4j.email.PIControllerMain [-verbose] -send:google -receive:yahoo -help
28 *
29 * This will send emails using google, and receive using yahoo.
30 * Do check the file email.properties for the different values associated with email servers.
31 *
32 * @param args See above
33 */
34 public static void main(String[] args)
35 {
36 for (int i=0; i<args.length; i++)
37 {
38 if ("-verbose".equals(args[i]))
39 {
40 verbose = true;
41 System.setProperty("verbose", "true");
42 }
43 else if (args[i].startsWith("-send:"))
44 providerSend = args[i].substring("-send:".length());
45 else if (args[i].startsWith("-receive:"))
46 providerReceive =args[i].substring("-receive:".length());
47 else if ("-help".equals(args[i]))
48 {
49 System.out.println("Usage:");
50 System.out.println(" java pi4j.email.PIControllerMain -verbose -send:google -receive:yahoo -help");
51 System.exit(0);
52 }
53 }
54
55 PIControllerMain lmc = new PIControllerMain();
56 GPIOController piController = new GPIOController(lmc);
57 EmailReceiver receiver = new EmailReceiver(providerReceive); // For Google, pop must be explicitely enabled at the account level
58 try
59 {
60 System.out.println("Waiting for instructions.");
61 boolean keepLooping = true;
62 while (keepLooping)
63 {
64 List<String> received = receiver.receive();
65 if (verbose || received.size() > 0)
66 System.out.println(SDF.format(new Date()) + " - Retrieved " + received.size() + " message(s).");
67 for (String s : received)
68 {
69 // System.out.println(s);
70 String operation = "";
71 try
72 {
73 JSONObject json = new JSONObject(s);
74 operation = json.getString("operation");
75 }
76 catch (Exception ex)
77 {
78 System.err.println(ex.getMessage());
79 System.err.println("Message is [" + s + "]");
80 }
81 if ("exit".equals(operation))
82 {
83 keepLooping = false;
84 System.out.println("Will exit next batch.");
85 // break;
86 }
87 else
88 {
89 if ("turn-green-on".equals(operation))
90 {
91 System.out.println("Turning green on");
92 piController.switchGreen(true);
93 }
94 else if ("turn-green-off".equals(operation))
95 {
96 System.out.println("Turning green off");
97 piController.switchGreen(false);
98 }
99 else if ("turn-yellow-on".equals(operation))
100 {
101 System.out.println("Turning yellow on");
102 piController.switchYellow(true);
103 }
104 else if ("turn-yellow-off".equals(operation))
105 {
106 System.out.println("Turning yellow off");
107 piController.switchYellow(false);
108 }
109 try { Thread.sleep(1000L); } catch (InterruptedException ie) { ie.printStackTrace(); }
110 }
111 }
112 }
113 piController.shutdown();
114 System.out.println("Done.");
115 System.exit(0);
116 }
117 catch (Exception ex)
118 {
119 ex.printStackTrace();
120 }
121 }
122
123 public void manageEvent(GpioPinDigitalStateChangeEvent event)
124 {
125 if (sender == null)
126 sender = new EmailSender(providerSend);
127 try
128 {
129 String mess = "{ pin: '" + event.getPin() + "', state:'" + event.getState() + "' }";
130 System.out.println("Sending:" + mess);
131 sender.send(sender.getEmailDest().split(","),
132 sender.getEventSubject(),
133 mess);
134 }
135 catch (Exception ex)
136 {
137 ex.printStackTrace();
138 }
139 }
140 }
Wiring |
Attention!:
GPIO pin 1 is the pin #12
GPIO pin 4 is the pin #16
GPIO pin 2 is the pin #13
The two leds need a 220 Ohms resistor inline between their anode (+) and the GPIO pin they're connected on.
Their cathode (-) is connected on the Ground (pin #6)
Demonstration |
An ethernet cable would have done the same job.
Also notice that there is no keyboard, mouse, nor screen connected to the device.
We used
ssh to connect to a Linux session, from which we started the Java program, in background.
The Raspberry PI, connected to a breadboard.
Prompt> sudo ./run -send:google -receive:google [&]
Hint: there is an help option.
Prompt> ./run -help
Usage:
java pi4j.email.PIControllerMain -verbose -send:google -receive:yahoo -help
Prompt>
The run script looks like this:
#!/bin/bash
CP=./classes
CP=$CP:/home/pi/pi4j/pi4j-distribution/target/distro-contents/lib/pi4j-core.jar
CP=$CP:./lib/javax.mail_1.1.0.0_1-4-4.jar
CP=$CP:./lib/json.jar
#
java -classpath $CP pi4j.email.LedControllerMain $*
Notice the different components on the breadboard:
- A green led
- A yellow led
- A push button
Event on the Raspberry PI side. Button pushed.
Two emails have been sent:
from : olivier.lediouris@gmail.com
subject: PI Event
content: { pin: '"GPIO 2" <GPIO 2>', state:'HIGH' }
from : olivier.lediouris@gmail.com
subject: PI Event
content: { pin: '"GPIO 2" <GPIO 2>', state:'LOW' }
Now, you send the following email (in plain text), from your laptop, desktop, smart phone, tablet, what not:
to : olivier.lediouris@gmail.com
subject: PI Request
content: { operation: "turn-green-on" }
The email is received by the Raspberry PI, the green led is turned on.
And you receive an acknowledgement, by email:
from : olivier.lediouris@gmail.com
subject: PI Robot Ack
content: Your request [{operation:"turn-green-on"}] is being taken care of.
Now you send the following email:
to : olivier.lediouris@gmail.com
subject: PI Request
content: { operation: "turn-yellow-on" }
The email is received by the Raspberry PI, the yellow led is turned on.
And you receive an acknowledgement, by email:
from : olivier.lediouris@gmail.com
subject: PI Robot Ack
content: Your request [{operation:"turn-yellow-on"}] is being taken care of.
Now you send the following emails:
to : olivier.lediouris@gmail.com
subject: PI Request
content: { operation: "turn-yellow-off" }
to : olivier.lediouris@gmail.com
subject: PI Request
content: { operation: "turn-green-off" }
to : olivier.lediouris@gmail.com
subject: PI Request
content: { operation: "exit" }
Everything off, program terminated.
All leds are turned off, and the program exits.
Done! Back to base.
Resources
- Raspberry PI
- PI4J
- The sources of this project
- The project, in Google Code