
写真登録とsmtpを介したインターネットへの統合により、冷蔵庫を違法な侵入から保護する簡単なシステムを組み立てましょう。 キッチンで本物のインターネットを手配しましょう!
同じ機能は、体重を減らしている人に役立ちます。 システムはトラブルメーカーと違反の可能性の瞬間の写真を撮ります。 冷蔵庫の開封は、リードリレー、冷蔵庫を開けた状態で従来のウェブカメラを使用したビデオ録画の助けを借りて検出します。 侵入者が正確に答えを残さないように、一連の写真をメールボックスに送信します。
記事の概要
- ハードウェア
- ソフトウェア部
- グルーヴィーに
- Javaで
- この知識でさらに生きる方法は?
ハードウェア
リードスイッチ-セキュリティシステム用。
ウェブカメラ-Logitech C310があります。サポートされているVideo4Linuxサブシステムはすべてサポートします
Raspberry Pi 3 Model B-WiFiが組み込まれているため、USBハブは不要です。
リードスイッチは、ピン番号17と15の間に接続する必要があります。 スキームに従って GPIO3と+ 3.3Vの間。
ソフトウェア部
オープンソースフレームワークのApache Camelとそのコンポーネントで、Rhiot for JVMは、クローゼットの中に散らばるシングルボードコンピューターの使用を見つけるために多くのことをしました。 その言語を使用して構成を記述し、既製のコンポーネントからシステム内の信号/データの「ルート」を組み立てれば十分です。Camelはそれをアプリケーションに変換します。
JVMでのモノのインターネットのための開発に関する前回の記事で、私は Camelの例を約束しましたが 、今日は約束を守ります! このプロジェクトの背後にあるアイデアは、Raspberry-Piの例を使用した侵入者検出に触発されています。 リードスイッチのみがアクセス可能であり、通常のボタンと同様にプログラムで動作します。I2Cプロトコルは不要です。
RouteBuilderを使用して、ルートを作成します。 キャメルのデータのソースとレシーバーはURLとして記述され、各コンポーネント/プロトコルについて、 ページ上のコンポーネントの形式の説明を読むことができます 。
- controlbusは、ルート管理のコンポーネントです。 私たちの場合、これを使用して写真の撮影を開始および停止します。
- pi4j-gpio- pi4jライブラリを使用して、ラズベリーのGPIOから信号を受信します。
- Webカメラ -タイマーコンポーネントによって決定される時間間隔でWebカメラからフレームを受信します。
- smtps-電子メールメッセージを送信します。
camelContext.start()は、コンポーネントを初期化し、ルートを開始します。 リードスイッチ接点の開放への反応は非常に簡単です:

hawt.ioのリードスイッチに対する反応の視覚化

写真をhawt.ioのメールに送信する写真登録のルート

addEventNotifier()により、ルートイベントをインターセプトできます。 ルートの開始と停止に応答し、アラームのステータスに関するメッセージをメールボックスに送信します。
メールがmail.ruサーバーにない場合は、SMTPホスト、メールのポートを見つけ、「smtps://smtp.mail.ru:465」の代わりにそれらを入力します。
また、同じキャメルルートで写真の顔を探しましたが、Raspberry PI 3モデルBでさえこのタスクで遅くなります。
コードスニペットはhawt.io Webコンソールを起動して、アプリケーションを監視および制御します。
MavenClassLoader.usingCentralRepo() .forMavenCoordinates('io.hawt:hawtio-app:2.0.0').loadClass('io.hawt.app.App') Thread.currentThread().setContextClassLoader(hawtIoConsole.getClassLoader()) hawtIoConsole.main('--port','10090')
ほぼ200のコンポーネントの機能では不十分な場合、Apache Camel用の新しいコンポーネントの開発は非常に簡単です。 私は最近、JVMのプログラムからLinuxCNCを実行しているCNCマシンにコマンドを送信するキャメルgcodeプロジェクトでこれを行いました。
グルーヴィーに
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() } }
Javaで
Javaで同じことを行うには、より多くの文字、ファイル、そしてもちろんReflection APIが必要でした。
クラス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); } } }); } }
ビルドするために必要なもの:
プロジェクトの依存関係を持つpom.xml
<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>
Raspberry Pi 3 Model Bで結果を実行する
SDカードでLinux Raspbianをビルドすると、奇跡的にすでにOracleのJava 8が含まれています。 WiFi経由でインターネット接続をセットアップするか、パッチコードで接続し、ボード上のRJ-45コネクタ経由でイーサネットネットワーク経由でインターネットへのアクセスを設定します。
したがって、インストール全体は単純なコマンドで構成されます。
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
そしてプログラムを起動します:
java -Dlogin=..._...@mail.ru -Dpassword=******* -jar groovy-grape-aether-2.4.5.4.jar AlarmSystem.groovy
または、コマンド履歴に表示されないように、ユーザー名とパスワードをスクリプトに入力するだけです。
def login = ... def password = ...
スクリプトを開始した直後に、「GPIO読み取り」ルートはリードスイッチからの信号を待って開始され、Webカメラとの2番目の「RaspberryPIアラーム」ルートは一時停止します。
あなたはウェブコンソールでそれを見ることができます...

jconsoleを脇に置くこともできます。 結局のところ、jvmスレッドとメトリックはhawt.ioで表示できます。


この監視コンソールはhttp:// Raspberry ADDRESS:10090 / hawtio /で入手できます。
Javaバージョンは、mavenを使用して構築する必要があります。 または、次のように、トリックに移動して、動的な依存関係を解決するスクリプトとしてJavaプログラムを実行できます。
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
java-as-script-1.0.jarがどのように機能するか、およびそれを使用して他に何ができるかについては、別の記事になります。
この知識でさらに生きる方法は?
Apache Camelは、さまざまな周辺機器やインターネットサービス用の既製のコンポーネントが多数あるため、ラピッドプロトタイピングの優れたツールであることが判明しました。 通常、統合用のエンタープライズアプリケーションで使用されますが、現代のシングルボードコンピューターやモノのインターネットソリューションでも、システムを開発する他のアプローチとは異なります。 試してみてください。特にGroovyでは気に入っていただけるでしょう!
このプロジェクトは、githubのアラームシステムリポジトリで利用でき、Apache Camelの公式Webサイトの「Camel and the IoT(Internet of Things)」セクションで紹介されています。