📜 ⬆️ ⬇️

Alarm for fridge. Not life, but “raspberry” with RaspberryPi 3

Dusted for a month on my shelf Raspberry Pi 3 with integrated Wi-Fi. The resources of the processor and the amount of memory are already enough to run demanding programs. How to quickly develop and run on it your program consisting of just one small file with sending a photo to the mail and a web monitoring server?



We will assemble a simple system for protecting the refrigerator against unauthorized entry with photo registration and integration into the Internet via smtp. We will arrange a real Internet of things in the kitchen!

The same function will be useful for losing weight. The system will take photographs of the intruder of the kitchen calm and the moment of possible offense. Opening the refrigerator will be detected using a reed switch, video recording using a conventional web camera in the light of an open refrigerator. So that the violator doesn’t get away from the answer, we will send a series of his photos to the mailbox.
')

Summary of the article



Hardware


Reed switch - any for the security system.
Webcam - I have a Logitech C310, any supported Video4Linux subsystem will do.
Raspberry Pi 3 Model B - there is a built-in WiFi and no USB hub is needed.

The reed switch must be connected between contact No. 17 and No. 15 - i.e. between GPIO3 and + 3.3V according to the scheme .

Software part


In the open source framework, Apache Camel and its components, Rhiot for JVM did a lot to find the use of a single-board computer gathering dust in the closet. It is enough, using its language to describe the configuration, to assemble the “route” signals / data components in the system from the ready components and Camel will turn it into an application.

In my last article on the development of the Internet of things in the JVM, I promised an example for Camel and today I keep my promise! The idea of ​​this project is inspired by the example of “Intruder detection with Raspberry-Pi” . Only the reed switch is more accessible and programmatically to work with it as well as with the usual button - no need for I2C protocol.

Using RouteBuilder create a route. Sources and receivers of data in camel are described as a URL and for each component / protocol the description of the format of any component can be read on the page .


camelContext.start () initializes the components and starts the route. It is very simple to react to the opening of the contact of the reed switch:



Visualization of the reaction to the reed switch in hawt.io


The route is the same photo registration with sending a snapshot to the mail in hawt.io


addEventNotifier () allows us to intercept route events. We will respond to starting and stopping the route and send a message about the status of the alarm to the mailbox.

If your mail is not on the mail.ru server, then find the smtp host, port for your mail and enter them instead of "smtps: //smtp.mail.ru: 465".

I also tried to look for the face on the photo in the same Camel route, but even the Raspberry PI 3 model B slows down on this task.

The code snippet runs the hawt.io web console to monitor and manage the application:

MavenClassLoader.usingCentralRepo() .forMavenCoordinates('io.hawt:hawtio-app:2.0.0').loadClass('io.hawt.app.App') Thread.currentThread().setContextClassLoader(hawtIoConsole.getClassLoader()) hawtIoConsole.main('--port','10090') 

If the functionality of almost two hundred components is not enough for you, then developing your own new component for Apache Camel is quite easy. I recently did this in the camel-gcode project for sending commands to a CNC machine running LinuxCNC from a program in the JVM.

On groovy


AlarmSystem.groovy
 @Grab('org.apache.camel:camel-groovy:2.18.0') @Grab('org.apache.camel:camel-core:2.18.0') @Grab('org.apache.camel:camel-mail:2.18.0') @Grab('io.rhiot:camel-webcam:0.1.4') @Grab('io.rhiot:camel-pi4j:0.1.4') @Grab('org.slf4j:slf4j-simple:1.6.6') import org.apache.camel.builder.RouteBuilder import org.apache.camel.impl.DefaultAttachment import org.apache.camel.impl.DefaultCamelContext import org.apache.camel.management.event.CamelContextStartedEvent import org.apache.camel.management.event.CamelContextStoppedEvent import org.apache.camel.support.EventNotifierSupport import javax.mail.util.ByteArrayDataSource import com.github.igorsuhorukov.smreed.dropship.MavenClassLoader def login = System.properties['login'] def password = System.properties['password'] def camelContext = new DefaultCamelContext() camelContext.setName('Alarm system') def mailEndpoint = camelContext.getEndpoint("smtps://smtp.mail.ru:465?username=${login}&password=${password}&contentType=text/html&debugMode=true") camelContext.addRoutes(new RouteBuilder() { def void configure() { from('pi4j-gpio://3?mode=DIGITAL_INPUT&pullResistance=PULL_DOWN').routeId('GPIO read') .choice() .when(header('CamelPi4jPinState').isEqualTo("LOW")) .to("controlbus:route?routeId=RaspberryPI Alarm&action=resume") .otherwise() .to("controlbus:route?routeId=RaspberryPI Alarm&action=suspend"); from("timer://capture_image?delay=200&period=5000") .routeId('RaspberryPI Alarm') .to("webcam:spycam?resolution=HD720") .setHeader('to').constant(login) .setHeader('from').constant(login) .setHeader('subject').constant('alarm image') .process{ def attachment = new DefaultAttachment(new ByteArrayDataSource(it.in.body, 'image/jpeg')); it.in.setBody("<html><head></head><body><img src=\"cid:alarm-image.jpeg\" /> ${new Date()}</body></html>"); attachment.addHeader("Content-ID", '<alarm-image.jpeg>'); it.in.addAttachmentObject("alarm-image.jpeg", attachment); //set CL to avoid javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed Thread.currentThread().setContextClassLoader( getClass().getClassLoader() ); } .to(mailEndpoint) } }) registerLifecycleActions(camelContext, mailEndpoint, login) camelContext.start() def hawtIoConsole = MavenClassLoader.usingCentralRepo() .forMavenCoordinates('io.hawt:hawtio-app:2.0.0').loadClass('io.hawt.app.App') Thread.currentThread().setContextClassLoader(hawtIoConsole.getClassLoader()) hawtIoConsole.main('--port','10090') void registerLifecycleActions(camelContext, mailEndpoint, login) { camelContext.getManagementStrategy().addEventNotifier(new EventNotifierSupport() { boolean isEnabled(EventObject event) { return event instanceof CamelContextStartedEvent | event instanceof CamelContextStoppedEvent } void notify(EventObject event) throws Exception { def status = event instanceof CamelContextStartedEvent ? 'up' : 'down' if ('up' == status){ def suspendEndpoint = camelContext.getEndpoint("controlbus:route?routeId=RaspberryPI Alarm&action=suspend") suspendEndpoint.createProducer().process(suspendEndpoint.createExchange()) } def message = mailEndpoint.createExchange(); message.in.setHeader('to', login) message.in.setHeader('from', login) message.in.setHeader('subject', "Alarm system is ${status}") message.in.setBody("System is ${status}: ${new Date()}"); mailEndpoint.createProducer().process(message) } }) addShutdownHook { camelContext.stop() } } 

In java


To do the same on java it took more letters, files and of course the Reflection API.

Class com.github.igorsuhorukov.alarmsys.AlarmSystem:
AlarmSystem.java

 package com.github.igorsuhorukov.alarmsys; //dependency:mvn:/com.github.igor-suhorukov:mvn-classloader:1.8 //dependency:mvn:/org.apache.camel:camel-core:2.18.0 //dependency:mvn:/org.apache.camel:camel-mail:2.18.0 //dependency:mvn:/io.rhiot:camel-webcam:0.1.4 //dependency:mvn:/io.rhiot:camel-pi4j:0.1.4 //dependency:mvn:/org.slf4j:slf4j-simple:1.6.6 import com.github.igorsuhorukov.smreed.dropship.MavenClassLoader; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultAttachment; import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.management.event.CamelContextStartedEvent; import org.apache.camel.management.event.CamelContextStoppedEvent; import org.apache.camel.support.EventNotifierSupport; import javax.mail.util.ByteArrayDataSource; import java.lang.reflect.Method; import java.util.Date; import java.util.EventObject; class AlarmSystem { public static void main(String[] args) throws Exception{ String login = System.getProperty("login"); String password = System.getProperty("password"); DefaultCamelContext camelContext = new DefaultCamelContext(); camelContext.setName("Alarm system"); Endpoint mailEndpoint = camelContext.getEndpoint(String.format("smtps://smtp.mail.ru:465?username=%s&password=%s&contentType=text/html&debugMode=true", login, password)); camelContext.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { from("pi4j-gpio://3?mode=DIGITAL_INPUT&pullResistance=PULL_DOWN").routeId("GPIO read") .choice() .when(header("CamelPi4jPinState").isEqualTo("LOW")) .to("controlbus:route?routeId=RaspberryPI Alarm&action=resume") .otherwise() .to("controlbus:route?routeId=RaspberryPI Alarm&action=suspend"); from("timer://capture_image?delay=200&period=5000") .routeId("RaspberryPI Alarm") .to("webcam:spycam?resolution=HD720") .setHeader("to").constant(login) .setHeader("from").constant(login) .setHeader("subject").constant("alarm image") .process(new Processor() { @Override public void process(Exchange it) throws Exception { DefaultAttachment attachment = new DefaultAttachment(new ByteArrayDataSource(it.getIn().getBody(byte[].class), "image/jpeg")); it.getIn().setBody(String.format("<html><head></head><body><img src=\"cid:alarm-image.jpeg\" /> %s</body></html>", new Date())); attachment.addHeader("Content-ID", "<alarm-image.jpeg>"); it.getIn().addAttachmentObject("alarm-image.jpeg", attachment); //set CL to avoid javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed Thread.currentThread().setContextClassLoader( getClass().getClassLoader() ); } }).to(mailEndpoint); } }); registerLifecycleActions(camelContext, mailEndpoint, login); camelContext.start(); Class<?> hawtIoConsole = MavenClassLoader.usingCentralRepo() .forMavenCoordinates("io.hawt:hawtio-app:2.0.0").loadClass("io.hawt.app.App"); Thread.currentThread().setContextClassLoader(hawtIoConsole.getClassLoader()); Method main = hawtIoConsole.getMethod("main", String[].class); main.setAccessible(true); main.invoke(null, (Object) new String[]{"--port","10090"}); } private static void registerLifecycleActions(final DefaultCamelContext camelContext, final Endpoint mailEndpoint, final String login) { camelContext.getManagementStrategy().addEventNotifier(new EventNotifierSupport() { public boolean isEnabled(EventObject event) { return event instanceof CamelContextStartedEvent | event instanceof CamelContextStoppedEvent; } public void notify(EventObject event) throws Exception { String status = event instanceof CamelContextStartedEvent ? "up" : "down"; if ("up".equals(status)){ Endpoint suspendEndpoint = camelContext.getEndpoint("controlbus:route?routeId=RaspberryPI Alarm&action=suspend"); suspendEndpoint.createProducer().process(suspendEndpoint.createExchange()); } Exchange message = mailEndpoint.createExchange(); message.getIn().setHeader("to", login); message.getIn().setHeader("from", login); message.getIn().setHeader("subject", "Alarm system is "+status); message.getIn().setBody("System is "+status+": "+new Date()); mailEndpoint.createProducer().process(message); } }); Runtime.getRuntime().addShutdownHook(new Thread(){ @Override public void run(){ try { camelContext.stop(); } catch (Exception e) { System.exit(-1); } } }); } } 


To build the need:

pom.xml with project dependencies
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.github.igor-suhorukov</groupId> <artifactId>alarm-system</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>com.github.igor-suhorukov</groupId> <artifactId>mvn-classloader</artifactId> <version>1.8</version> </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-core</artifactId> <version>2.18.0</version> </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-mail</artifactId> <version>2.18.0</version> </dependency> <dependency> <groupId>io.rhiot</groupId> <artifactId>camel-webcam</artifactId> <version>0.1.4</version> </dependency> <dependency> <groupId>io.rhiot</groupId> <artifactId>camel-pi4j</artifactId> <version>0.1.4</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.6.6</version> </dependency> </dependencies> </project> 


Run the result on the Raspberry Pi 3 Model B


The linux Raspbian build on the SD card already miraculously contains Java 8 from Oracle. Configure the connection to the Internet via WiFi or connect with a patchcord and configure the access to the Internet via the ethernet network via the RJ-45 connector on the board.

So the whole installation will consist of simple commands:

 wget https://repo1.maven.org/maven2/com/github/igor-suhorukov/groovy-grape-aether/2.4.5.4/groovy-grape-aether-2.4.5.4.jar wget https://raw.githubusercontent.com/igor-suhorukov/alarm-system/master/AlarmSystem.groovy 

And run the program:

 java -Dlogin=..._...@mail.ru -Dpassword=******* -jar groovy-grape-aether-2.4.5.4.jar AlarmSystem.groovy 

Or you can simply enter your username and password in the script, so as not to shine them in the command history:

 def login = ... def password = ... 

Immediately after launching the script, the “GPIO read” route waits for a signal from the reed switch and is launched, and the second route “RaspberryPI Alarm” with a webcam is paused.

This can be viewed in the web console ...


You can also put jconsole aside. After all flows and metrics of jvm can be looked in hawt.io



This monitoring console is available at http: // ADDRESS_MALINA: 10090 / hawtio /

Java version needs to be built using maven. Or you can go to the trick and run a Java program as a script with dynamic dependency resolution as follows:

java -Dlogin = ... YOUR_EMAIL ... @ mail.ru -Dpassword = ******* -DscriptPath = https: //raw.githubusercontent.com/igor-suhorukov/alarm-system/master/src/ main / java / com / github / igorsuhorukov / alarmsys / AlarmSystem.java -jar java-as-script-1.0.jar

About how java-as-script-1.0.jar works and what else you can do with it will be a separate article.

How to live on with this knowledge?



Apache Camel turned out to be an excellent tool for rapid prototyping, since there are many ready-made components for various peripherals and Internet services. Although it is usually used in enterprise applications for integration, but even on modern single-board computers and solutions for the “Internet of things”, it will give odds to other approaches for developing systems. Just "break it out" and you will like it, especially with Groovy!

The project is available in the github repository alarm-system and appeared on the official Apache Camel website in the “Camel and the IoT (Internet of Things)” section .

Source: https://habr.com/ru/post/314898/


All Articles