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