工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

プールコントローラー

コンポーネントと消耗品

>
Raspberry Pi2モデルB
× 1
PNY 16GB Turbo MicroSDXC CL10
× 1
SparkFun Arduino Pro Mini 328-5V / 16MHz
× 1
SainSmart 5V4チャンネルソリッドステートリレーボード
× 1
Arduino用Tolako5vリレーモジュール
× 1
DS18b20防水温度センサー
× 1
4.7kオーム抵抗器-1/4ワット-5%- 4K7(10個)
× 1
Raspberry Pi USBWIFIドングル
× 1
>
男性から女性への拡張1-フィートUSB
× 1
>
アメリカンバルブCL40PK6ナンバー40クランプ、6パック
× 1
J-B Weld 8272 MarineWeld Marine Epoxy-2 oz
× 1
シートワッシャー
× 2
マイクロUSB電源ウォールチャージャーACアダプター
× 1

必要なツールとマシン

Printrbot Simple
エンクロージャーとセンサーマウントの作成に使用
Arduinoミニポート用のFtdiUsb-Ttlシリアルアダプターモジュール
Arduino MiniProにスケッチをアップロードするために使用

アプリとオンラインサービス

>
Microsoft Windows 10 IoT Core
Microsoft Visual Studio 2015
Microsoft IIS
Arduino IDE
OneWireライブラリ
ダラス温度ライブラリ
openHABオープンソースホームオートメーションソフトウェア

このプロジェクトについて

自動プールコントローラー

2回、3か月の間に、プールポンプのタイマーが故障しました。これがきっかけで、このプロジェクトを作成しました。それらのタイマーを交換するコストは120ドルを超え、私がそれを示さなければならなかったのは、私にほとんど制御を与えず、高い失敗率を与えるタイマーだけでした。また、太陽熱温水器の温度センサーに障害が発生し、さらに30ドルの費用がかかりました。

<図>

私は、プールポンプがいつ稼働するかをより詳細に制御できる、費用効果の高い自動プールコントローラーを作成できることを知っていました。既存のタイマーの単純な日時ではなく、ポンプがいつ稼働するかについて、より多くの変数が必要でした。また、プールポンプを自動化するだけでなく、プール環境のさまざまな側面のステータスを監視できるようにしたかったのです。さらなる目標は、任意のデバイスを使用して、どこからでもこれらのタスクを実行できるようにすることでした。

私が作成したプロジェクトは、Windows 10 IoT Core、リレー、Arduino Mini Pro、温度センサー、配線、3D印刷コンポーネントを実行するRaspberry Piを利用しているため、非常に費用対効果が高くなっています。以前の2つのタイマーと太陽温度センサーに支払った金額よりもはるかに少ない費用でこのプロジェクトを完了しました。

プールポンプ制御(ACコンポーネント)

<図> <図>

私は、Windows 10 IoTCoreを実行しているRaspberryPiからソリッドステートリレーを制御することからプロジェクトを開始しました。これらのリレーを使用すると、プールポンプなどのAC(交流)コンポーネントを制御できます。ソリッドステートリレーは、古いタイマーが使用していた既存の30AmpACリレーを制御します。プールポンプの回路を設計およびテストした後、プールの滝、プールや庭の照明など、他のACコンポーネントを制御するための追加機能を作成しました。プロジェクトのこの部分を設計することで、これらすべての要素をリモートで制御できました。家族や、滝をオンにしたり、プールや庭のライトをオンにしたり、プールポンプのタイマーを設定したりするために、コントロールボックスを物理的に開く必要はもうありません。

<図>

プールコントローラーエンクロージャー

私の息子はプールコントローラーエンクロージャーを設計し、3Dプリンターを使用して作成し、RaspberryPiとソリッドステートリレーの両方がコントローラーボックス内にしっかりと収まるようにしました。

<図> <図> <図> <図>

温度センサー

<図>

myprojectの設計目標の1つは、曜日と時間に加えて変数に基づいた制御を可能にすることでした。外気温度、太陽熱温水器、プールの水温を考慮して、ポンプをいつ稼働させ、いつ停止させるかを決定できるようにしたかったのです。このタイプの操作が重要になる場合の1つの例は、外気温が非常に低く、氷点下に近い場合です。プールの水温も氷点下に近い場合は、パイプが凍結してシステムに損傷を与えるのを防ぐために、プールとウォーターフォールポンプが稼働していることを確認する必要があります。このプロジェクトを利用することで、家にいなくてもこれを成し遂げることができます。これを実装するために、myprojectに温度センサーを組み込みました。 I2Cinterfaceを介してプールとウォーターフォールポンプを制御する同じRaspberryPiにそのデータを送信するArduinoMiniProを利用してこれらのセンサーを読みました。

外気温度センサー

外気温度センサーは私が最初に組み込んだセンサーでした。繰り返しになりますが、息子が3Dプリンターでセンサーマウントを設計して印刷しました。彼はPLAとABSの両方を試しましたが、ABSは耐候性が高く、ガラス転移温度が高いため耐熱性が高いため、実際にはより効果的に機能します。 少なくとも75%の塗りつぶしで印刷するようにしてください。 センサーは、上記の概略図のように接続されました。

<図> <図>

水温センサー

次に、プールの水とソーラーヒーターの温度センサーを組み込みました。これにより、プロジェクトは、ユーザーに表示される水温データを収集できるだけでなく、特定のコンポーネントがいつ実行されたか、または停止していたかを判断するための変数をさらに提供できます。まず、センサーマウントが設計され、3Dプリントされました。先に述べたように、ABSは実際には、耐候性と耐熱性が優れているため、より効果的に機能します。また、少なくとも75%のインフィルを使用していることを確認してください

<図>

水温センサーの構築と設置

水温センサーマウントを印刷した後、皿穴ドリルビットを使用してセンサー穴の周囲に45度の領域を作成しました。これにより、JB溶接部が付着する表面積を増やすことができます。ドリルビットのラフカットによりJB溶接部の保持力が向上したように見えるため、3Dプリントのデザインを変更するよりも、ドリルビットを使用してこれを行うことを好みました。

<図>

次のステップは、温度センサーをマウントの下部から約3/4インチ伸びるまでマウントに挿入することでした。シートワッシャーを追加して、所定の位置に保持します。

<図>

次に、マウントの上部にJB溶接を充填し、24時間乾燥させます。

<図>

JBウェルドが乾くのを少なくとも24時間待った後、水温センサーを設置する時が来ました。

重要な注意: 水温センサーを設置する前に、すべてのポンプがオフになっていることを確認してください。

すべてのウォーターポンプがオフになっていることを確認したら、水温センサーを設置するエリアから水圧を取り除くことができるバルブを開くことをお勧めします。これにより、設置が大幅に容易になります(また、体をドライに保ちます)。

プールの配管に5/16 "の穴を開けます。水温センサーを取り付け、2つのクランプを使用してしっかりと固定します。同じ間違いをしないで、クランプを締めすぎないでください。締めすぎるとセンサーマウントが押しつぶされます。閉じるバルブをオンにしてポンプをオンにします。漏れがないか確認します。

<図> <図> <図> <図>

ソーラーヒーターバルブ制御

<図>

温度センサーを設置した後、太陽熱温水器のバルブ制御を設計して設置することができました。ソーラーヒーターは、前述の他のプールコンポーネントで使用されるAC電圧とは対照的に、DC電圧を利用します。これには、ACリレーの代わりにDCリレーを制御する必要がありました。概念は似ていますが、必要なリレーは異なります。プロジェクトに使用するリレーが、制御しているデバイスで使用される正しいタイプの電圧を制御することを確認してください。

この制御により、プールの水を屋根のソーラーパネルに向けることができます。外気温が60度を超える場合にのみ、水をパネルに向けたいと思います。水がパネルに迂回されたら、戻ってくる水がプールの水より少なくとも2度暖かいことを確認してください。そうでなければ、水をパネルに汲み上げるのはエネルギーの無駄です。

このコントロールの配線と接続は、Pool Controller DC Componentsschematicで提供されています。

アプリケーション開発

RaspberryPiにWindows10IoT Coreをインストールした後、それを管理するために使用されるWebサーバーが組み込まれていることに気付きました。これはIISの簡略版かどうか疑問に思いましたか?もしそうなら、私はIISでいくつかの安らかなサービスを書いて、このプロジェクトのためにそれらを呼び出すことができます。多くのウェブ検索と多くの調査の結果、それは不可能であるように思われました。そのアプローチは私が好むアプローチですが、現時点では実現可能ではないようです。

別のアプローチで、「BlinkyWebServer」の例と「DrussBlog」に関する記事を確認しました。HTTPGETおよびPOSTリクエストに応答する単純なHTTPWebサーバーとして機能するヘッドレスWindows10IoTコアバックグラウンドアプリケーションを構築することにしました。 。

数日以内に、私は実用的なプロトタイプを手に入れました。これは私のプロジェクトが成功する可能性があるという大きな自信を与えてくれました。そこで、このアーキテクチャを進めることにしました。 Visual Studio 2015デバッガーを使用してコードを徹底的にテストした後、アプリケーションを簡単にデプロイできるという印象を受けました。

アプリケーションのデプロイ

これは私が苦労した点ですので、そのような困難を回避する方法をお見せしたいと思います。私のアプリケーションはVisualStudio 2015デバッガーで徹底的にテストされたため、モードをデバッグからリリースに変更するだけでアプリケーションを展開できるという印象を受けました。私はこのアプローチを試しましたが、実際にはアプリケーションをデプロイしてデバッグモードで起動しました。次に、デバッグを停止し、AppXManagerからアプリケーションを実行しようとしました。これを試みても成功しませんでした。「アプリケーションを初期化できませんでした」という一般的なエラーが発生しました。

この問題の解決策は、現在のデプロイメントを削除してから、代わりにAppXManagerからアプリケーションをインストールすることです。これには多くの時間がかかったので、この問題を回避するのに役立つことを願っています。

アプリケーションはVisualStudio 2015デバッグモードで問題なく実行されましたが、最初のHTTP要求を受信すると停止します。これのトラブルシューティングに多くの時間を費やしましたが、なぜこれが発生するのかまだわかりません。

このプロジェクトを完了するためのプレッシャーを感じて、私は自分のプロジェクトを「BlinkyWebServer」の例のように変更することにしました。私の実装では、WebサーバーがGPIOピンを制御してI2Cインターフェイス(画面アプリケーションではない)を読み取ることを計画していたため、Windows 10 IoTCore画面アプリケーションの必要性はわかりませんでした。私のプロジェクトで行ったことは、スクリーンアプリケーションにWebサーバーを起動させることでした。次に、Webサーバーはメッセージを画面アプリケーションに送り返し、サーバーが受信したHTTP呼び出しを確認できるようにします。このアプローチは堅実なようで、最初の試みで使用したコードとまったく同じです。

ユーザーインターフェイス

最後に、事実上すべてのデバイスで実行されるHTML制御プログラムを作成しました。これにより、プールポンプ、滝、プールライトを制御できるだけでなく、追加のセンサーをどこからでも監視できます。

<図>

その後、OpenHABを利用して、この追加のインターフェイスを提供するサイトマップを作成しました。

<図>

私が作成したのと同じくらい、私のプロジェクトについて読んで楽しんでいただけたと思います。ありがとう。

YouTube、Vimeo、またはVineのリンクをクリックし、Enterキーを押します

コード

  • I2Cを使用した温度センサー用のArduinoスケッチ
  • PoolWebServer-BackgroundTask.cs
  • PoolWebServer-Devices.cs
  • PoolWebServer-Sensors.cs
  • PoolWebService- MainPage.xaml.cs
  • PoolWebService-App.xaml.cs
  • OpenHABサイトマップ
  • OpenHABアイテム
I2C Java を使用した温度センサー用のArduinoスケッチ
DS18b20温度センサーを読み取り、I2Cインターフェースを介して要求されたときにデータを送信するコード。
 #include  #include  #include  #define SLAVE_ADDRESS 0x40 // GPIOピンを定義constantsconst int POOL_PIN =3; const int SOLAR_PIN =5; const int OUTSIDE_PIN =7; // I2Cインターフェースのバッファーの長さを定義constint I2C_BUFFER_LEN =24; //重要なMAXは32です!!! // OneWireをロード-独自のダラス半導体センサープロトコル-ライセンスは不要OneWirepoolTemp(POOL_PIN); OneWire solarTemp(SOLAR_PIN); OneWireoutsideTemp(OUTSIDE_PIN); //ダラスをロード-独自のダラスセンサープロトコルを利用onewire-ライセンスは不要ですvoid setup(void){//温度センサーバスに接続poolSensor.begin(); solarSensor.begin(); OutsideSensor.begin(); // I2Cインターフェースを開始しますWire.begin(SLAVE_ADDRESS); Wire.onRequest(requestEvent);} void loop(void){//定義された間隔ごとに1回、温度センサーを読み取る時間を監視します// 1秒ごとより速く読み取らないでください。彼らはその高速なunsignedlong currMillis =millis();に応答できません。 if(currMillis-prevMillis>インターバル){prevMillis =currMillis; readTemperatures(); }} void readTemperatures(){// 3つの温度センサーすべてを読み取るpoolSensor.requestTemperatures(); solarSensor.requestTemperatures(); OutsideSensor.requestTemperatures(); //温度データを文字列に保存します//古いデータを確実に上書きするためにバッファの全長までパディングします//データは「88.99 | 78.12 | 100.00」の形式です。ここで「PoolTemp | SolarTemp | OutsideTemp」temperatureData =padRight(String(poolSensor.getTempFByIndex(0))+ "|" + String(solarSensor.getTempFByIndex(0))+ "|" + String(outsideSensor.getTempFByIndex(0))、I2C_BUFFER_LEN);} String padRight(String inStr 、int inLen){while(inStr.length() 
PoolWebServer-BackgroundTask.cs C#
HTTPPOSTおよびGETリクエストに応答するHTTPサーバーを定義します
 // Copyright(c)Microsoft。 All rights reserved.using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Http; using Windows.Foundation.Collections; using Windows.ApplicationModel.Background; usingWindows.ApplicationModel。 AppService; using Windows.System.Threading; using Windows.Networking.Sockets; using System.IO; using Windows.Storage.Streams; using System.Threading.Tasks; using System.Runtime.InteropServices.WindowsRuntime; using Windows.Foundation; using Windows.Devices.Gpio; namespace WebServerTask {public Sealed class WebServerBGTask:IBackgroundTask {public void Run(IBackgroundTaskInstance taskInstance){//キャンセルハンドラーをバックグラウンドタスクに関連付けます。 taskInstance.Canceled + =OnCanceled; //タスクインスタンスから延期オブジェクトを取得しますserviceDeferral =taskInstance.GetDeferral(); var appService =taskInstance.TriggerDetails as AppServiceTriggerDetails; if(appService!=null &&appService.Name =="App2AppComService"){appServiceConnection =appService.AppServiceConnection; appServiceConnection.RequestReceived + =OnRequestReceived; }} // PoolWebServiceアプリから送信されたメッセージリクエストを処理しますprivateasync void OnRequestReceived(AppServiceConnection sender、AppServiceRequestReceivedEventArgs args){var message =args.Request.Message; string command =message ["Command"] as string; switch(コマンド){case "Initialize":{Sensors.InitSensors(); Devices.InitDevices(); var messageDeferral =args.GetDeferral(); //呼び出し元に返す結果を設定しますvarreturnMessage =new ValueSet(); //ポート8888でHTTPServerの新しいインスタンスを定義しますHttpServerserver =new HttpServer(8888、appServiceConnection); IAsyncAction asyncAction =Windows.System.Threading.ThreadPool.RunAsync((workItem)=> {//サーバーを起動しますserver.StartServer();}); //成功のステータスでPoolWebServiceに応答しますreturnMessage.Add( "Status"、 "Success"); var responseStatus =await args.Request.SendResponseAsync(returnMessage); messageDeferral.Complete();壊す; } case "Quit":{//サービスは終了するように求められました。サービスの延期を提供します//プラットフォームがバックグラウンドタスクを終了できるようにしますserviceDeferral.Complete();壊す; }}} private void OnCanceled(IBackgroundTaskInstance sender、BackgroundTaskCancellationReason reason){//クリーンアップして終了する準備をします} BackgroundTaskDeferral serviceDeferral; AppServiceConnection appServiceConnection; } // HTTP WebServerを定義するクラスpublicSealed class HttpServer:IDisposable {// HTTPデータを読み取るためのバッファーを作成しますprivateconst uint BufferSize =8192; //プライベートintポートでリッスンするポート=8888; //プライベート読み取り専用StreamSocketListenerリスナーへのリスナー; //ステータス情報をPoolControllerWebServiceに送り返すための接続privateAppServiceConnection appServiceConnection; public HttpServer(int serverPort、AppServiceConnection connection){listener =new StreamSocketListener();ポート=serverPort; appServiceConnection =接続; // HTTP接続のイベントハンドラーを追加listener.ConnectionReceived + =(s、e)=> ProcessRequestAsync(e.Socket); } //リストナーを開始するための呼び出しpublicvoid StartServer(){#pragma warning disable CS4014 listener.BindServiceNameAsync(port.ToString()); #pragma warning restore CS4014} public void Dispose(){listener.Dispose(); } private async void ProcessRequestAsync(StreamSocket socket){try {StringBuilder request =new StringBuilder(); //(IInputStream input =socket.InputStream){byte [] data =new byte [BufferSize];を使用して着信データを取得しますIBuffer buffer =data.AsBuffer(); uint dataRead =BufferSize; //すべての着信データを読み取りますwhile(dataRead ==BufferSize){await input.ReadAsync(buffer、BufferSize、InputStreamOptions.Partial); request.Append(Encoding.UTF8.GetString(data、0、data.Length)); dataRead =buffer.Length; }} //(IOutputStream output =socket.OutputStream){string requestMethod =request.ToString();を使用してデータの応答の処理を開始します。 string [] requestParts ={""}; if(requestMethod!=null){//リクエストをパーツにビークアップしますrequestMethod =requestMethod.Split( '\ n')[0]; requestParts =requestMethod.Split( ''); } // HTTP GETSメソッドとPOSTメソッドに応答するのは、(requestParts [0] =="GET")await WriteGetResponseAsync(requestParts [1]、output);の場合のみです。 else if(requestParts [0] =="POST")await WritePostResponseAsync(requestParts [1]、output);それ以外の場合は、WriteMethodNotSupportedResponseAsync(requestParts [1]、output);を待ちます。 }} catch(Exception){}} //すべてのHTTPGETのプライベート非同期タスクWriteGetResponseAsync(string request、IOutputStream os){bool urlFound =false; byte [] bodyArray =null;文字列responseMsg =""; //リクエストが有効なリクエストURLのいずれかに一致するかどうかを確認し、レスポンスメッセージスイッチを作成します(request.ToUpper()){case "/ SENSORS / POOLTEMP":responseMsg =Sensors.PoolTemperature; urlFound =true;壊す;ケース "/ SENSORS / SOLARTEMP":responseMsg =Sensors.SolarTemperature; urlFound =true;壊す;ケース "/ SENSORS / OUTSIDETEMP":responseMsg =Sensors.OutsideTemperature; urlFound =true;壊す;ケース "/ DEVICES / POOLPUMP / STATE":responseMsg =Devices.PoolPumpState; urlFound =true;壊す;ケース "/ DEVICES / WATERFALLPUMP / STATE":responseMsg =Devices.PoolWaterfallState; urlFound =true;壊す;ケース "/ DEVICES / POOLLIGHTS / STATE":responseMsg =Devices.PoolLightsState; urlFound =true;壊す;ケース "/ DEVICES / YARDLIGHTS / STATE":responseMsg =Devices.YardLightsState; urlFound =true;壊す;ケース "/ DEVICES / POOLSOLAR / STATE":responseMsg =Devices.PoolSolarValveState; urlFound =true;壊す;デフォルト:urlFound =false;壊す; } bodyArray =Encoding.UTF8.GetBytes(responseMsg); WriteResponseAsync(request.ToUpper()、responseMsg、urlFound、bodyArray、os);を待ちます。 } //すべてのHTTPPOSTのプライベート非同期タスクを処理しますWritePostResponseAsync(string request、IOutputStream os){bool urlFound =false; byte [] bodyArray =null;文字列responseMsg =""; //リクエストが有効なリクエストURLのいずれかに一致するかどうかを確認し、応答メッセージスイッチを作成します(request.ToUpper()){case "/ DEVICES / POOLPUMP / OFF":Devices.PoolPumpPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes( "OFF"); responseMsg ="OFF"; urlFound =true;壊す;ケース "/ DEVICES / POOLPUMP / ON":Devices.PoolPumpPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes( "ON"); responseMsg ="ON"; urlFound =true;壊す;ケース "/ DEVICES / WATERFALLPUMP / OFF":Devices.PoolWaterfallPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes( "OFF"); responseMsg ="OFF"; urlFound =true;壊す;ケース "/ DEVICES / WATERFALLPUMP / ON":Devices.PoolWaterfallPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes( "ON"); responseMsg ="ON"; urlFound =true;壊す;ケース "/ DEVICES / POOLLIGHTS / OFF":Devices.PoolLightsPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes( "OFF"); responseMsg ="OFF"; urlFound =true;壊す;ケース "/ DEVICES / POOLLIGHTS / ON":Devices.PoolLightsPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes( "ON"); responseMsg ="OFF"; urlFound =true;壊す;ケース "/ DEVICES / YARDLIGHTS / OFF":Devices.YardLightsPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes( "OFF"); responseMsg ="OFF"; urlFound =true;壊す;ケース "/ DEVICES / YARDLIGHTS / ON":Devices.YardLightsPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes( "ON"); responseMsg ="OFF"; urlFound =true;壊す;ケース "/ DEVICES / POOLSOLAR / OFF":Devices.PoolSolarValvePinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes( "OFF"); responseMsg ="OFF"; urlFound =true;壊す;ケース "/ DEVICES / POOLSOLAR / ON":Devices.PoolSolarValvePinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes( "ON"); responseMsg ="ON"; urlFound =true;壊す;デフォルト:bodyArray =Encoding.UTF8.GetBytes( ""); urlFound =false;壊す; } await WriteResponseAsync(request.ToUpper()、responseMsg、urlFound、bodyArray、os); } //サポートされていないHTTPメソッドの応答を書き込むprivateasync Task WriteMethodNotSupportedResponseAsync(string request、IOutputStream os){bool urlFound =false; byte [] bodyArray =null; bodyArray =Encoding.UTF8.GetBytes( ""); WriteResponseAsync(request.ToUpper()、 "NOT SUPPORTED"、urlFound、bodyArray、os);を待ちます。 } // HTTP GETおよびPOSTのプライベート非同期タスクの応答を書き込みますWriteResponseAsync(string RequestMsg、string ResponseMsg、bool urlFound、byte [] bodyArray、IOutputStream os){try // appServiceは1日ほどで終了します。 httpサーバーが引き続き応答するように個別にキャッチしてみましょう{varupdateMessage =new ValueSet(); updateMessage.Add( "Request"、RequestMsg); updateMessage.Add( "Response"、ResponseMsg); var responseStatus =await appServiceConnection.SendMessageAsync(updateMessage); } catch(Exception){} try {MemoryStream bodyStream =new MemoryStream(bodyArray); using(Stream response =os.AsStreamForWrite()){string header =GetHeader(urlFound、bodyStream.Length.ToString()); byte [] headerArray =Encoding.UTF8.GetBytes(header); response.WriteAsync(headerArray、0、headerArray.Length);を待ちます。 if(urlFound)await bodyStream.CopyToAsync(response); response.FlushAsync();を待ちます}} catch(Exception){}} //見つかったURLと見つからなかったURLのHTTPヘッダーテキストを作成しますstringGetHeader(bool urlFound、string bodyStreamLength){string header; if(urlFound){header ="HTTP / 1.1 200 OK \ r \ n" + "Access-Control-Allow-Origin:* \ r \ n" + "Content-Type:text / plain \ r \ n" + " Content-Length: "+ bodyStreamLength +" \ r \ n "+"接続:close \ r \ n \ r \ n "; } else {header ="HTTP / 1.1 404 Not Found \ r \ n" + "Access-Control-Allow-Origin:* \ r \ n" + "Content-Type:text / plain \ r \ n" + "Content -長さ:0 \ r \ n "+"接続を閉じる\ r \ n \ r \ n "; }ヘッダーを返します。 }}} 
PoolWebServer-Devices.cs C#
クラスは、すべてのデバイスと、それらが接続されているGPIOピンを
 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Windows.Devices.Gpio; namespace WebServerTask {//クラスは、すべてのデバイスとそれらが接続されているGPIOピンを定義します。 public static class Devices {// GPIOピン番号を定義しますprivateconst int POOL_PUMP_PIN =12; private const int POOL_WATERFALL_PIN =13; private const int POOL_LIGHTS_PIN =16; private const int YARD_LIGHTS_PIN =18; private const int POOL_SOLAR_VALVE_PIN =22; // GPIOピンを定義しますprivatestatic GpioPin poolPumpPin;プライベート静的GpioPinpoolWaterfallPin;プライベート静的GpioPinpoolLightsPin;プライベート静的GpioPinyardLightsPin;プライベート静的GpioPinpoolSolarValvePin; //プールポンプに割り当てられたGPIOピンのプロパティpublicstatic GpioPinValue PoolPumpPinValue {get {return poolPumpPin.Read(); //ピンを読み取るとHighまたはLowを返します} set {if(poolPumpPin.Read()!=value)//変更している場合にのみピンを設定しますpoolPumpPin.Write(value); }} //プールポンプのステータスを読み取るプロパティONまたはOFFpublic static string PoolPumpState {get {return GetState(PoolPumpPinValue、GpioPinValue.High); //状態を取得します}} //ウォーターフォールポンプに割り当てられたGPIOピンのプロパティpublicstatic GpioPinValue PoolWaterfallPinValue {get {return poolWaterfallPin.Read(); } set {if(poolWaterfallPin.Read()!=value)poolWaterfallPin.Write(value); }} //ウォーターフォールポンプのステータスを読み取るプロパティONまたはOFFpublic static string PoolWaterfallState {get {return GetState(PoolWaterfallPinValue、GpioPinValue.High); }} //プールライトに割り当てられたGPIOピンのプロパティpublicstatic GpioPinValue PoolLightsPinValue {get {return poolLightsPin.Read(); } set {if(poolLightsPin.Read()!=value)poolLightsPin.Write(value); }} //プールライトのステータスを読み取るプロパティONまたはOFFpublic static string PoolLightsState {get {return GetState(PoolLightsPinValue、GpioPinValue.High); }} //ソーラーをオン/オフするためにバルブに割り当てられたGPIOピンのプロパティpublicstatic GpioPinValue PoolSolarValvePinValue {get {return poolSolarValvePin.Read(); } set {if(poolSolarValvePin.Read()!=value)poolSolarValvePin.Write(value); }} //ソーラーバルブのステータスを読み取るプロパティONまたはOFFpublic static string PoolSolarValveState {get {return GetState(PoolSolarValvePinValue、GpioPinValue.High); }} //ヤードライトに割り当てられたGPIOピンのプロパティpublicstatic GpioPinValue YardLightsPinValue {get {return yardLightsPin.Read(); } set {if(yardLightsPin.Read()!=value)yardLightsPin.Write(value); }} //ヤードライトのステータスを読み取るプロパティONまたはOFFpublic static string YardLightsState {get {return GetState(YardLightsPinValue、GpioPinValue.High); }} //使用されるすべてのGPIOピンを初期化するpublicstatic void InitDevices(){var gpio =GpioController.GetDefault(); if(gpio!=null){//これらのピンはアクティブハイリレー上にあります。 poolPumpPin =gpio.OpenPin(POOL_PUMP_PIN);を開始するときに、すべてをOFFに設定します。 poolPumpPin.Write(GpioPinValue.Low); poolPumpPin.SetDriveMode(GpioPinDriveMode.Output); poolWaterfallPin =gpio.OpenPin(POOL_WATERFALL_PIN); poolWaterfallPin.Write(GpioPinValue.Low); poolWaterfallPin.SetDriveMode(GpioPinDriveMode.Output); poolLightsPin =gpio.OpenPin(POOL_LIGHTS_PIN); poolLightsPin.Write(GpioPinValue.Low); poolLightsPin.SetDriveMode(GpioPinDriveMode.Output); yardLightsPin =gpio.OpenPin(YARD_LIGHTS_PIN); yardLightsPin.Write(GpioPinValue.Low); yardLightsPin.SetDriveMode(GpioPinDriveMode.Output); poolSolarValvePin =gpio.OpenPin(POOL_SOLAR_VALVE_PIN); poolSolarValvePin.Write(GpioPinValue.Low); poolSolarValvePin.SetDriveMode(GpioPinDriveMode.Output); }} //それに基づいてデバイスの状態を取得しますActiveState // ActiveStateは、GPIOピンでデバイスをHighまたはLowにするために必要なものを意味しますprivate static string GetState(GpioPinValue value、GpioPinValue ActiveState){string state ="OFF"; if(value ==ActiveState)state ="ON";状態を返します。 }}} 
PoolWebServer-Sensors.cs C#
すべての温度センサーとそれらを読み取るために使用されるI2Cインターフェースを定義するクラス
 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Windows.Devices.Enumeration; using Windows.Devices.I2c; namespace WebServerTask {//すべての温度センサーとそれらを読み取るために使用されるI2Cインターフェイスを定義するクラスpublicstatic class Sensors {private static I2cDevice Device;プライベート静的タイマーperiodicTimer; // Arduino MiniProから温度データを読み取る頻度privatestatic int ReadInterval =4000; // 4000 =4秒//温度データを保持する変数privatestatic string poolTemperature ="--.--";プライベート静的文字列solarTemperature ="--.--";プライベート静的文字列outsideTemperature ="--.--"; //温度データを公開するプロパティpublicstatic string PoolTemperature {get {//タイマーが変数に書き込もうとしている場合に備えて、変数をロックしますlock(poolTemperature){return poolTemperature; }} set {// HTTPサーバーが変数から読み取ろうとしている場合に備えて、変数をロックしますlock(poolTemperature){poolTemperature =value; }}} //温度データを公開するプロパティpublicstatic string SolarTemperature {get {//タイマーが変数に書き込もうとしている場合に備えて、変数をロックしますlock(solarTemperature){return solarTemperature; }} set {// HTTPサーバーが変数から読み取ろうとしている場合に備えて、変数をロックしますlock(solarTemperature){solarTemperature =value; }}} //温度データを公開するプロパティpublicstatic string OutsideTemperature {get {//タイマーが変数に書き込もうとしている場合に備えて、変数をロックしますlock(outsideTemperature){returnoutsideTemperature; }} set {// HTTPサーバーが変数から読み取ろうとしている場合に備えて、変数をロックしますlock(outsideTemperature){outsideTemperature =value; }}} // I2C接続を初期化し、タイマーを開始してI2Cデータを読み取りますasync public static void InitSensors(){// I2C接続をセットアップしますArduinovar settings =new I2cConnectionSettings(0x40); // Arduinoアドレスsettings.BusSpeed =I2cBusSpeed.StandardMode;文字列aqs =I2cDevice.GetDeviceSelector( "I2C1"); var dis =await DeviceInformation.FindAllAsync(aqs);デバイス=await I2cDevice.FromIdAsync(dis [0] .Id、settings); // Arduinoから定期的に温度を読み取るタイマーを作成しますperiodicTimer =new Timer(Sensors.TimerCallback、null、0、ReadInterval); } //タイムコールバックを処理するprivatestatic void TimerCallback(object state){byte [] RegAddrBuf =new byte [] {0x40}; byte [] ReadBuf =new byte [24]; // I2C接続を読み取りますtry {Device.Read(ReadBuf); //データを読み取ります} catch(Exception){} //応答を解析します//データは "88.99 | 78.12 | 100.00"の形式になります。ここで "PoolTemp | SolarTemp | OutsideTemp" char [] cArray =System.Text.Encoding。 UTF8.GetString(ReadBuf、0、23).ToCharArray(); //バイトを文字列に変換c =new String(cArray).Trim(); string [] data =c.Split( '|'); //データを温度変数に書き込みますtry {if(data [0] .Trim()!="")PoolTemperature =data [0]; if(data [1] .Trim()!="")SolarTemperature =data [1]; if(data [2] .Trim()!="")OutsideTemperature =data [2]; } catch(例外){}}}} 
PoolWebService- MainPage.xaml.cs C#
WebServerを起動するアプリのメインページ
 // Copyright(c)Microsoft。 All rights reserved.using System; using Windows.ApplicationModel.AppService; using Windows.Devices.Gpio; using Windows.Foundation.Collections; using Windows.UI.Core; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml .Media; namespace PoolWebService {パブリックシールされた部分クラスMainPage:Page {AppServiceConnection appServiceConnection; public MainPage(){InitializeComponent(); InitializeAppSvc(); } private async void InitializeAppSvc(){string WebServerStatus ="PoolWebServerを開始できませんでした。AppServiceConnectionStatusは成功しませんでした。"; // AppServiceConnectionを初期化しますappServiceConnection =new AppServiceConnection(); appServiceConnection.PackageFamilyName ="PoolWebServer_hz258y3tkez3a"; appServiceConnection.AppServiceName ="App2AppComService"; //初期化リクエストを送信しますvarres =await appServiceConnection.OpenAsync(); if(res ==AppServiceConnectionStatus.Success){var message =new ValueSet(); message.Add( "Command"、 "Initialize"); var response =await appServiceConnection.SendMessageAsync(message); if(response.Status!=AppServiceResponseStatus.Success){WebServerStatus ="PoolWebServerを開始できませんでした。";新しいException( "メッセージの送信に失敗しました");をスローします。 } appServiceConnection.RequestReceived + =OnMessageReceived; WebServerStatus ="PoolWebServerが開始されました。"; } await Dispatcher.RunAsync(CoreDispatcherPriority.Normal、()=> {txtWebServerStatus.Text =WebServerStatus;}); } private async void OnMessageReceived(AppServiceConnection sender、AppServiceRequestReceivedEventArgs args){var message =args.Request.Message; string msgRequest =message ["Request"] as string; string msgResponse =message ["Response"] as string; await Dispatcher.RunAsync(CoreDispatcherPriority.Normal、()=> {txtRequest.Text =msgRequest; txtResponse.Text =msgResponse;}); }}} 
PoolWebService-App.xaml.cs C#
 // Copyright(c)Microsoft。 All rights reserved.using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Windows.ApplicationModel; using Windows.ApplicationModel.Activation; using Windows.Foundation; Windows.Foundation.Collectionsを使用する; Windows.UI.Xamlを使用する; Windows.UI.Xaml.Controlsを使用する; Windows.UI.Xaml.Controls.Primitivesを使用する; Windows.UI.Xaml.Dataを使用する; Windows.UI.Xamlを使用するInput; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; namespace PoolWebService {///  ///デフォルトのApplicationクラスを補足するアプリケーション固有の動作を提供します。 /// 封印された部分クラスApp:Application {///  ///シングルトンアプリケーションオブジェクトを初期化します。これは、作成されたコードの最初の行///実行されるため、main()またはWinMain()と論理的に同等です。 ///  public App(){InitializeComponent();サスペンド+ =OnSuspending; } ///  ///アプリケーションがエンドユーザーによって正常に起動されたときに呼び出されます。特定のファイルを開くためにアプリケーションを起動するときなど、他のエントリポイント///が使用されます。 ///  /// 起動リクエストとプロセスの詳細。 protected override void OnLaunched(LaunchActivatedEventArgs e){#if DEBUG if(System.Diagnostics.Debugger。 IsAttached){DebugSettings.EnableFrameRateCounter =true; } #endif Frame rootFrame =Window.Current.Content as Frame; //ウィンドウにすでにコンテンツがある場合は、アプリの初期化を繰り返さないでください。//ウィンドウがアクティブであることを確認してくださいif(rootFrame ==null){//ナビゲーションコンテキストとして機能するフレームを作成し、最初のページに移動しますrootFrame =new Frame(); //デフォルトの言語を設定しますrootFrame.Language =Windows.Globalization.ApplicationLanguages.Languages [0]; rootFrame.NavigationFailed + =OnNavigationFailed; if(e.PreviousExecutionState ==ApplicationExecutionState.Terminated){// TODO:以前に中断されたアプリケーションから状態をロード} //フレームを現在のウィンドウに配置しますWindow.Current.Content =rootFrame; } if(rootFrame.Content ==null){//ナビゲーションスタックが復元されない場合は、最初のページに移動し、//必要な情報をナビゲーションとして渡すことで新しいページを構成します//パラメータrootFrame.Navigate(typeof(MainPage )、e.Arguments); } //現在のウィンドウがアクティブであることを確認しますWindow.Current.Activate(); } ///  ///特定のページへのナビゲーションが失敗したときに呼び出される///  /// ナビゲーションに失敗したフレーム /// ナビゲーションの失敗に関する詳細 void OnNavigationFailed(object sender、NavigationFailedEventArgs e){throw new Exception( "Failed to load Page" + e.SourcePageType.FullName); } ///  ///アプリケーションの実行が一時停止されているときに呼び出されます。アプリケーションの状態は///メモリの内容をそのままにして///アプリケーションを終了するか再開するかを知らずに保存されます。 ///  /// 一時停止リクエストのソース。 /// 一時停止リクエストの詳細。 private void OnSuspending(object sender、SuspendingEventArgs e){var deferral =e.SuspendingOperation.GetDeferral(); // TODO:アプリケーションの状態を保存し、バックグラウンドアクティビティを停止しますdeferral.Complete(); }}} 
OpenHABサイトマップ JavaScript
openHAB構成で使用されるサンプルサイトマップ
 sitemapdefault label ="Windows 10 IoT" {Frame label ="" {Text label ="Pool" icon ="swimmingpool" {Switch item =PoolPump mappings =[ON ="ON"、 OFF ="OFF"]スイッチitem =WaterFallマッピング=[ON ="ON"、OFF ="OFF"]スイッチitem =PoolLightsマッピング=[ON ="ON"、OFF ="OFF"]テキストitem =pooltempテキストアイテム=solartemp Text item =outsidetemp}}} 
OpenHABアイテムプレーンテキスト
サンプルアイテムopenHAB構成
 Switch PoolPump "Pool Pump" (grp1){http ="> [ON:POST:http://  / DEVICES / POOLPUMP / ON]> [OFF:POST:http ://  / DEVICES / POOLPUMP / OFF] <[http://  / DEVICES / POOLPUMP / STATE:1500:REGEX((。*?))] "、autoupdate =" true "}スイッチWaterFall "ウォーターフォール" <ウォーターフォール>(grp1){http ="> [ON:POST:http://  / DEVICES / WATERFALLPUMP / ON]> [OFF:POST:http://  / DEVICES / WATERFALLPUMP / OFF] <[http://  / DEVICES / WATERFALLPUMP / STATE:1500:REGEX((。*?))] "、autoupdate =" true "} Switch PoolLights" Pool Lights "(grp1){http ="> [ON:POST:http://  / DEVICES / POOLLIGHTS / ON]> [OFF:POST:http://  / DEVICES / POOLLIGHTS / OFF] <[http://  / DEVICES / POOLLIGHTS / STATE:1500:REGEX((。*?))] "、autoupdate =" true "} Number pooltemp" Pool Water Temp [%.2f F] "(grp1){http =" <[http://  / SENSORS / POOLTEMP:30000:REGEX((。*?))] "} Number solartemp" Solar Water Temp [%.2f F] "(grp1){http =" <[http://  / SENSORS / SOLARTEMP:30000:REGEX((。*?))] "}数値outsidetemp"外気温[%.2f F] "<温度>(grp1){http =" <[http://  / SENSORS / OUTSIDETEMP:30000:REGEX((。*?))] "} 
GitHubプロジェクトリポジトリ
フルVisualStudio2015プールコントローラープロジェクトhttps://github.com/mmackes/Windows-10-IoT-PoolController

カスタムパーツとエンクロージャー

気温を監視するためのDS18B20防水センサーを保持するためのマウント標準のプール配管にDS18B20防水センサーを保持するためのマウントRaspberryPiおよびリレー用のエンクロージャーRaspberryPiおよびリレー用のエンクロージャー

回路図

RaspberryPiをACリレーに接続する方法を示す概略図。プールポンプ、滝、プールライト、ACヤードライトを制御します RaspberryPiをDCリレーに接続する方法を示す概略図。太陽熱温水バルブを制御します。 RaspberryPiをArduinoMiniProおよび温度センサーに接続する方法を示す概略図。プールの水、ソーラーヒーターの水、外気の温度を監視します。

製造プロセス

  1. ラズベリーパイの温度監視
  2. Raspberry Pi2ウェザーステーション
  3. ラズベリーパイで温度を監視する
  4. SensorflareとRaspberryPiを備えた433MHzスマートホームコントローラー
  5. ラズベリーパイボール追跡
  6. ラズベリーパイユニバーサルリモコン
  7. RaspberryPiを使用したモーションセンサー
  8. ラズベリーパイのスライス
  9. サイクルチェイサー
  10. ラズベリーパイ土壌水分センサー
  11. ラズベリーパイ泥棒検出器