Manufaktur industri
Industri Internet of Things | bahan industri | Pemeliharaan dan Perbaikan Peralatan | Pemrograman industri |
home  MfgRobots >> Manufaktur industri >  >> Manufacturing Technology >> Proses manufaktur

Pengontrol Kolam

Komponen dan persediaan

Raspberry Pi 2 Model B
× 1
PNY 16GB Turbo MicroSDXC CL10
× 1
SparkFun Arduino Pro Mini 328 - 5V/16MHz
× 1
Papan Relai Solid State SainSmart 5V 4-Channel
× 1
Modul Relay 5v Tolako untuk Arduino
× 1
Sensor Suhu Tahan Air DS18b20
× 1
Resistor 4.7k Ohm - 1/4 Watt - 5% - 4K7 (10 Buah)
× 1
Dongle WIFI USB Raspberry Pi
× 1
Ekstensi Pria Ke Wanita Usb 1 Kaki
× 1
American Valve CL40PK6 Nomor 40 Clamp, 6-Pack
× 1
J-B Weld 8272 MarineWeld Marine Epoxy - 2 oz
× 1
Pencuci Kursi
× 2
Adaptor AC Pengisi Daya Dinding Micro USB Power Supply
× 1

Alat dan mesin yang diperlukan

Printrbot Sederhana
Digunakan untuk membuat enklosur dan dudukan sensor
Modul Adaptor Serial Ftdi Usb ke Ttl untuk Arduino Mini Port
Digunakan untuk mengunggah sketsa ke Arduino Mini Pro

Aplikasi dan layanan online

Microsoft Windows 10 IoT Core
Microsoft Visual Studio 2015
Microsoft IIS
Arduino IDE
Pustaka OneWire
Perpustakaan Suhu Dallas
perangkat lunak otomatisasi rumah sumber terbuka openHAB

Tentang proyek ini

Pengontrol Pool Otomatis

Dua kali, dalam waktu tiga bulan, timer untuk pompa kolam saya gagal. Ini menginspirasi saya untuk membuat proyek ini. Biaya penggantian pengatur waktu itu lebih dari $120 dan yang harus saya tunjukkan hanyalah pengatur waktu yang memberi saya kendali yang sangat kecil dan tingkat kegagalan yang tinggi. Saya juga mengalami kegagalan sensor suhu pada pemanas air tenaga surya saya dengan biaya tambahan $30.

Saya tahu bahwa saya dapat membuat pengontrol kolam otomatis yang hemat biaya yang memberi saya lebih banyak kendali saat pompa kolam saya bekerja. Saya ingin memiliki lebih banyak variabel tentang kapan pompa bekerja daripada waktu dan hari sederhana dari pengatur waktu yang ada. Saya juga ingin tidak hanya dapat mengotomatiskan pompa kolam saya, tetapi juga memantau status berbagai aspek lingkungan kolam saya. Sasaran selanjutnya adalah dapat menyelesaikan tugas-tugas ini dari mana saja menggunakan perangkat apa pun.

Proyek yang saya buat sangat hemat biaya karena menggunakan Raspberry Pi yang menjalankan Windows 10 IoT Core, Relay, Arduino Mini Pro serta sensor suhu, kabel, dan komponen cetak 3D. Saya menyelesaikan proyek ini dengan uang yang jauh lebih sedikit daripada yang saya bayarkan untuk dua penghitung waktu sebelumnya dan sensor suhu matahari.

Kontrol Pompa Kolam Renang (Komponen AC)

Saya memulai proyek saya dengan mengontrol solid state relay dari Raspberry Pi saya yang menjalankan Windows 10 IoT Core. Relay ini memungkinkan saya untuk mengontrol komponen AC (Alternating Current) saya seperti pompa kolam. Relai solid state mengontrol relai AC 30Amp yang ada yang digunakan oleh pengatur waktu lama. Setelah merancang dan menguji sirkuit untuk pompa kolam, saya membuat fungsionalitas tambahan untuk mengontrol komponen AC lainnya seperti air terjun kolam, serta lampu kolam dan halaman. Dengan bagian proyek yang dirancang ini, saya dapat mengontrol semua elemen ini dari jarak jauh. Anggota keluarga saya atau saya tidak perlu lagi membuka kotak kontrol secara fisik untuk menyalakan air terjun, menyalakan lampu kolam atau halaman, atau menyetel pengatur waktu untuk pompa kolam.

Kandang Pengendali Kolam

Anak saya mendesain enklosur Pool Controller dan membuatnya menggunakan printer 3D kami dan memastikan bahwa Raspberry Pi dan solid state relay telah terpasang dengan aman di dalam kotak pengontrol.

Sensor Suhu

Salah satu tujuan desain untuk proyek saya adalah memungkinkan kontrol berdasarkan variabel selain Hari dan Waktu. Saya ingin dapat memperhitungkan suhu udara luar serta pemanas air tenaga surya dan suhu air kolam untuk menentukan kapan pompa harus bekerja dan kapan harus berhenti. Salah satu contoh ketika jenis operasi ini akan menjadi sangat penting adalah ketika suhu udara luar sangat dingin dan mendekati titik beku. Jika suhu air kolam juga mendekati titik beku, saya perlu memastikan kolam dan pompa air terjun saya bekerja untuk mencegah pipa membeku dan merusak sistem. Dengan menggunakan proyek ini saya akan dapat menyelesaikan ini bahkan ketika saya tidak di rumah. Untuk menerapkan ini, saya memasukkan sensor suhu ke myproject. Saya membaca sensor tersebut menggunakan Arduino Mini Pro yang mengirimkan data tersebut ke Raspberry Pi yang sama yang mengontrol pompa kolam dan air terjun melalui antarmuka I2C.

Sensor Suhu Udara Luar

Sensor suhu udara luar adalah sensor pertama yang saya masukkan. Sekali lagi, anak saya mendesain dan mencetak dudukan sensor pada printer 3D kami. Dia mencoba PLA dan ABS, ABS benar-benar bekerja lebih baik karena lebih tahan cuaca dan memiliki suhu transisi kaca yang lebih tinggi sehingga lebih tahan panas. Pastikan Anda mencetak dengan pengisian minimal 75%. Sensor terhubung seperti yang dijelaskan di atas dalam skema.

Sensor Suhu Air

Saya kemudian memasukkan sensor suhu air kolam dan pemanas matahari. Ini akan memungkinkan proyek untuk mengumpulkan data suhu air yang akan ditampilkan kepada pengguna serta memberikan variabel lebih lanjut untuk menentukan kapan komponen tertentu berjalan atau tidak. Pertama, dudukan sensor dirancang dan dicetak 3D. Seperti disebutkan sebelumnya, ABS sebenarnya bekerja lebih baik karena cuaca dan ketahanan panas yang lebih baik. Juga pastikan Anda menggunakan setidaknya 75% pengisi .

Membangun dan Memasang Sensor Suhu Air

Setelah mencetak dudukan sensor suhu air, saya menggunakan mata bor countersink untuk membuat area 45 derajat di sekitar lubang sensor. Ini akan memungkinkan JB Weld  memiliki lebih banyak area permukaan untuk dipatuhi. Saya lebih suka menggunakan mata bor untuk melakukan ini daripada mengubah desain cetak 3D karena potongan kasar mata bor tampaknya memberi JB Weld daya tahan yang lebih baik.

Langkah selanjutnya adalah memasukkan sensor suhu ke dudukan hingga memanjang sekitar 3/4" dari bagian bawah dudukan.  Tambahkan pencuci kursi untuk menahannya di tempatnya. 

Selanjutnya, isi bagian atas mount dengan JB Weld dan biarkan mengering selama 24 jam.

Setelah menunggu setidaknya 24 jam hingga JB Weld mengering, kini saatnya memasang sensor suhu air.

Catatan PENTING: Pastikan semua pompa mati sebelum mencoba memasang sensor suhu air!

Setelah memastikan semua pompa air mati, sebaiknya buka katup apa pun yang dapat menghapus tekanan air dari area tempat Anda memasang sensor suhu air.  Ini akan sangat memudahkan pemasangan (dan juga membuat Anda tetap kering).

Bor lubang 5/16" di pipa kolam.  Pasang sensor suhu air dan gunakan 2 klem untuk menahannya dengan kuat di tempatnya.  Jangan membuat kesalahan yang sama seperti yang saya lakukan dan mengencangkan klem terlalu kencang, pengencangan yang berlebihan akan menghancurkan dudukan sensor.  Tutup katup dan hidupkan pompa.  Periksa kebocoran.

Kontrol Katup Pemanas Surya

Setelah sensor suhu terpasang, saya kemudian dapat merancang dan memasang kontrol katup pemanas Air Tenaga Surya. Pemanas Tenaga Surya menggunakan tegangan DC sebagai lawan dari tegangan AC yang digunakan dengan komponen kolam lain yang disebutkan sebelumnya. Ini mengharuskan saya untuk mengontrol relai DC alih-alih relai AC. Konsepnya mirip, tetapi relai yang dibutuhkan berbeda. Pastikan relai yang Anda gunakan untuk proyek Anda akan mengontrol jenis voltase yang benar yang digunakan oleh perangkat yang Anda kendalikan.

Kontrol ini memungkinkan saya untuk mengarahkan air kolam ke panel surya di atap saya. Saya hanya ingin mengarahkan air ke panel ketika suhu udara luar di atas 60 derajat. Setelah air dialihkan ke panel, pastikan air yang kembali setidaknya 2 derajat lebih hangat dari air kolam. Jika tidak, pemborosan energi untuk memompa air ke panel.

Pengkabelan dan koneksi kontrol ini disediakan dalam skema Komponen DC Pool Controller.

Pengembangan Aplikasi

Setelah menginstal Windows 10IoT Core di Raspberry Pi saya, saya menyadari bahwa ia memiliki server web bawaan yang digunakan untuk mengelolanya. Saya bertanya-tanya apakah ini versi IIS yang dilucuti? Jika demikian, saya bisa saja menulis beberapa layanan yang menenangkan di IIS dan memanggil mereka untuk proyek ini. Setelah banyak pencarian web dan banyak penelitian, tampaknya tidak mungkin. Pendekatan itu akan menjadi salah satu yang saya sukai, tetapi tampaknya tidak layak untuk saat ini.

Mengambil pendekatan yang berbeda, saya meninjau contoh ”Blinky Web Server" dan artikel di ”Druss Blog”. Saya memutuskan untuk membuat Aplikasi Latar Belakang Inti Windows 10 IoT tanpa kepala yang bertindak sebagai Server Web HTTP sederhana yang menanggapi permintaan HTTP GET dan POST . 

Dalam beberapa hari, saya memiliki prototipe kerja. Ini memberi saya banyak keyakinan bahwa proyek saya bisa berhasil. Jadi saya memutuskan untuk bergerak maju dengan arsitektur ini. Setelah menguji kode saya secara menyeluruh melalui debugger Visual Studio 2015, saya mendapat kesan bahwa saya dapat dengan mudah menggunakan aplikasi saya.

Menerapkan Aplikasi

Ini adalah poin yang saya perjuangkan, jadi saya berharap dapat menunjukkan kepada Anda bagaimana menghindari kesulitan seperti itu. Karena Aplikasi saya telah diuji secara menyeluruh dalam debugger Visual Studio 2015, saya mendapat kesan bahwa saya hanya dapat mengubah mode dari Debug ke Rilis untuk menyebarkan aplikasi saya. Saya mencoba pendekatan ini dan itu sebenarnya menyebarkan aplikasi saya dan memulainya dalam mode Debug. Saya kemudian menghentikan debug dan mencoba menjalankan aplikasi dari AppX Manager. Saya tidak berhasil ketika saya mencoba ini, saya hanya akan mendapatkan kesalahan umum yang menyatakan, "Aplikasi gagal untuk menginisialisasi."

Solusi untuk masalah ini adalah menghapus penerapan saat ini dan kemudian menginstal aplikasi dari AppX Manager. Ini menghabiskan banyak waktu, jadi saya harap ini membantu Anda menghindari masalah itu.

Meskipun aplikasi berjalan dengan sempurna dalam mode debug Visual Studio 2015, itu akan mati setelah menerima permintaan HTTP pertama. Saya menghabiskan banyak waktu untuk mencoba memecahkan masalah ini dan masih tidak tahu mengapa ini terjadi.

Merasa tertekan untuk menyelesaikan proyek ini, saya memutuskan untuk mengubah proyek saya menjadi seperti contoh “Blinky Web Server”. Dalam implementasi saya, saya tidak melihat perlunya aplikasi layar Windows 10 IoT Core karena saya merencanakan server web untuk mengontrol pin GPIO dan membaca antarmuka I2C (bukan aplikasi layar). Apa yang saya lakukan dalam proyek saya adalah membuat aplikasi layar memulai server web. Server Web kemudian mengirim pesan kembali ke aplikasi layar sehingga saya dapat melihat panggilan HTTP apa yang diterima oleh server saya. Pendekatan ini tampaknya sangat kuat dan kodenya persis sama dengan yang saya gunakan dalam upaya awal saya.

Antarmuka Pengguna

Terakhir, saya membuat program kontrol HTML yang akan berjalan di hampir semua perangkat. Ini memungkinkan saya tidak hanya mengontrol pompa kolam, air terjun, dan lampu kolam, tetapi juga memantau sensor tambahan dari mana saja.

Kemudian, saya menggunakan OpenHAB dan membuat peta situs yang memberi saya antarmuka tambahan ini.

Saya harap Anda menikmati membaca tentang proyek saya sama seperti saya menciptakannya. Terima kasih.

Tautan YouTube, Vimeo, atau Vine, dan tekan Enter

Kode

  • Arduino Sketch untuk Sensor Suhu menggunakan I2C
  • PoolWebServer - BackgroundTask.cs
  • PoolWebServer - Devices.cs
  • PoolWebServer - Sensors.cs
  • PoolWebService- MainPage.xaml.cs
  • PoolWebService - App.xaml.cs
  • Peta Situs OpenHAB
  • Item OpenHAB
Arduino Sketch untuk Sensor Suhu menggunakan I2C Java
Kode untuk membaca sensor suhu DS18b20 dan mengirim data saat diminta melalui antarmuka I2C.
#include #include #include #define SLAVE_ADDRESS 0x40 //Tentukan pin GPIO constantsconst int POOL_PIN =3;const int SOLAR_PIN =5;const int OUTSIDE_PIN =7;//Menentukan panjang buffer untuk antarmuka I2Cconst int I2C_BUFFER_LEN =24; //PENTING MAX adalah 32!!!//Muat OneWire - protokol sensor semikonduktor dallas berpemilik - tidak diperlukan lisensiOneWire poolTemp(POOL_PIN);OneWire solarTemp(SOLAR_PIN);OneWire outsideTemp(OUTSIDE_PIN);//Muat Dallas - pemanfaatan protokol sensor dallas berpemilik onewire - tidak diperlukan lisensiDallasTemperature poolSensor(&poolTemp);DallasTemperature solarSensor(&solarTemp);DallasTemperature outsideSensor(&outsideTemp);//Define I2C bufferchar data[I2C_BUFFER_LEN];String temperatureData;//Define variable for timerlong previnterval =1000; void setup(void) { //Hubungkan ke bus sensor suhu poolSensor.begin(); solarSensor.begin(); luarSensor.begin(); //Mulai antarmuka I2C Wire.begin(SLAVE_ADDRESS); Wire.onRequest(requestEvent);}void loop(void) { //Pantau waktu untuk membaca sensor suhu setiap interval yang ditentukan //Jangan membacanya lebih cepat dari setiap 1 detik. mereka tidak dapat merespons long currMillis =millis() yang cepat tanpa tanda itu; if (currMillis - prevMillis> interval) { prevMillis =currMillis; bacaSuhu(); }}void readTemperatures() { //Baca ketiga sensor suhu poolSensor.requestTemperatures(); solarSensor.requestTemperatures(); luarSensor.requestTemperatures(); //Menyimpan data suhu dalam sebuah string //Kami memasukkan ke kanan sepanjang buffer untuk memastikan untuk menimpa data lama //Data dalam format "88.99|78.12|100.00" di mana "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.csC#
Mendefinisikan Server HTTP yang menanggapi permintaan HTTP POST dan GET
// Hak Cipta (c) Microsoft. Semua hak dilindungi undang-undang.menggunakan Sistem;menggunakan System.Collections.Generic;menggunakan System.Linq;menggunakan System.Text;menggunakan System.Net.Http;menggunakan Windows.Foundation.Collections;menggunakan Windows.ApplicationModel.Background;menggunakan Windows.ApplicationModel. AppService;menggunakan Windows.System.Threading;menggunakan Windows.Networking.Sockets;menggunakan System.IO;menggunakan Windows.Storage.Streams;menggunakan System.Threading.Tasks;menggunakan System.Runtime.InteropServices.WindowsRuntime;menggunakan Windows.Foundation;menggunakan Windows.Devices.Gpio;namespace WebServerTask{ kelas tersegel publik WebServerBGTask :IBackgroundTask { public void Run(IBackgroundTaskInstance taskInstance) { // Kaitkan penangan pembatalan dengan tugas latar belakang. taskInstance. Dibatalkan +=Dibatalkan; // Dapatkan objek penangguhan dari instance tugas serviceDeferral =taskInstance.GetDeferral(); var appService =taskInstance.TriggerDetails sebagai AppServiceTriggerDetails; if (appService !=null &&appService.Name =="App2AppComService") { appServiceConnection =appService.AppServiceConnection; appServiceConnection.RequestReceived +=OnRequestReceived; } } //Memproses permintaan pesan yang dikirim dari Aplikasi PoolWebService private async void OnRequestReceived(Pengirim AppServiceConnection, AppServiceRequestReceivedEventArgs args) { var message =args.Request.Message; perintah string =pesan["Perintah"] sebagai string; switch (perintah) { case "Inisialisasi":{ Sensors.InitSensors(); Perangkat.InitDevices(); var messageDeferral =args.GetDeferral(); //Menetapkan hasil untuk kembali ke pemanggil var returnMessage =new ValueSet(); //Tentukan contoh baru HTTPServer kami di Port 8888 HttpServer server =new HttpServer(8888, appServiceConnection); IAsyncAction asyncAction =Windows.System.Threading.ThreadPool.RunAsync( (workItem) => { //Memulai server Sever.StartServer(); }); //Menanggapi kembali PoolWebService dengan Status Sukses returnMessage.Add("Status", "Success"); var responseStatus =menunggu args.Request.SendResponseAsync(returnMessage); messageDeferral.Lengkap(); merusak; } case "Quit":{ //Layanan diminta untuk berhenti. Beri kami penangguhan layanan //sehingga platform dapat menghentikan tugas latar belakang serviceDeferral.Complete(); merusak; } } } private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) { //Bersihkan dan bersiap untuk keluar } BackgroundTaskDeferral serviceDeferral; AppServiceConnection appServiceConnection; } //Kelas untuk mendefinisikan kelas tersegel publik HTTP WebServer HttpServer :IDisposable { //Buat buffer untuk membaca data HTTP private const uint BufferSize =8192; //Port untuk mendengarkan pada private int port =8888; //Mendengarkan pendengar StreamSocketListener pribadi yang hanya bisa dibaca; //Koneksi untuk mengirim informasi status kembali ke PoolControllerWebService private AppServiceConnection appServiceConnection; public HttpServer(int serverPort, koneksi AppServiceConnection) { pendengar =new StreamSocketListener(); port =port server; appServiceConnection =koneksi; //Tambahkan event handler untuk pendengar koneksi HTTP.ConnectionReceived +=(s, e) => ProcessRequestAsync(e.Socket); } //Panggil untuk memulai listner public void StartServer() {#pragma warning nonaktifkan pendengar CS4014.BindServiceNameAsync(port.ToString());#pragma warning restore CS4014 } public void Dispose() { listener.Dispose(); } private async void ProcessRequestAsync(StreamSocket socket) { coba { StringBuilder request =new StringBuilder(); //Dapatkan data yang masuk menggunakan (IInputStream input =socket.InputStream) { byte[] data =new byte[BufferSize]; Buffer IBuffer =data.AsBuffer(); uint dataRead =Ukuran Buffer; //Baca semua data yang masuk saat (dataRead ==BufferSize) { menunggu input.ReadAsync(buffer, BufferSize, InputStreamOptions.Partial); request.Append(Encoding.UTF8.GetString(data, 0, data.Panjang)); dataRead =buffer.Panjang; } } //Mendapatkan data mulai memproses respons menggunakan (IOutputStream output =socket.OutputStream) { string requestMethod =request.ToString(); string[] requestParts ={ "" }; if (requestMethod !=null) { //Beakup permintaan ke dalam bagian requestMethod =requestMethod.Split('\n')[0]; requestParts =requestMethod.Split(' '); } //Kami hanya merespon HTTP GETS dan metode POST jika (requestParts[0] =="GET") menunggu WriteGetResponseAsync(requestParts[1], output); else if (requestParts[0] =="POST") menunggu WritePostResponseAsync(requestParts[1], output); lain menunggu WriteMethodNotSupportedResponseAsync(requestParts[1], output); } } catch (Pengecualian) { } } //Menangani semua tugas asinkron HTTP GET WriteGetResponseAsync(permintaan string, IOutputStream os) { bool urlFound =false; byte[] bodyArray =null; string responMsg =""; //Lihat apakah permintaan itu cocok dengan salah satu url permintaan yang valid dan buat sakelar pesan respons (request.ToUpper()) { case "/SENSORS/POOLTEMP":responseMsg =Sensors.PoolTemperature; urlDitemukan =benar; merusak; case "/SENSORS/SOLARTEMP":responseMsg =Sensors.SolarTemperature; urlDitemukan =benar; merusak; case "/SENSORS/OUTSIDETEMP":responseMsg =Sensors.OutsideTemperature; urlDitemukan =benar; merusak; case "/DEVICES/POOLPUMP/STATE":responseMsg =Devices.PoolPumpState; urlDitemukan =benar; merusak; case "/DEVICES/WATERFALLPUMP/STATE":responseMsg =Devices.PoolWaterfallState; urlDitemukan =benar; merusak; case "/DEVICES/POOLLIGHTS/STATE":responseMsg =Devices.PoolLightsState; urlDitemukan =benar; merusak; case "/DEVICES/YARDLIGHTS/STATE":responseMsg =Devices.YardLightsState; urlDitemukan =benar; merusak; case "/DEVICES/POOLSOLAR/STATE":responseMsg =Devices.PoolSolarValveState; urlDitemukan =benar; merusak; default:urlFound =salah; merusak; } bodyArray =Encoding.UTF8.GetBytes(responseMsg); menunggu WriteResponseAsync(request.ToUpper(), responseMsg, urlFound, bodyArray, os); } //Menangani semua tugas asinkron HTTP POST WritePostResponseAsync(permintaan string, IOutputStream os) { bool urlFound =false; byte[] bodyArray =null; string responMsg =""; //Lihat apakah permintaan itu cocok dengan salah satu url permintaan yang valid dan buat sakelar pesan respons (request.ToUpper()) { case "/DEVICES/POOLPUMP/OFF":Devices.PoolPumpPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes("OFF"); responseMsg ="MATI"; urlDitemukan =benar; merusak; case "/DEVICES/POOLPUMP/ON":Devices.PoolPumpPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes("ON"); responseMsg ="ON"; urlDitemukan =benar; merusak; case "/DEVICES/WATERFALLPUMP/OFF":Devices.PoolWaterfallPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes("OFF"); responseMsg ="MATI"; urlDitemukan =benar; merusak; case "/DEVICES/WATERFALLPUMP/ON":Devices.PoolWaterfallPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes("ON"); responseMsg ="ON"; urlDitemukan =benar; merusak; case "/DEVICES/POOLLIGHTS/OFF":Devices.PoolLightsPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes("OFF"); responseMsg ="MATI"; urlDitemukan =benar; merusak; case "/DEVICES/POOLLIGHTS/ON":Devices.PoolLightsPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes("ON"); responseMsg ="MATI"; urlDitemukan =benar; merusak; case "/DEVICES/YARDLIGHTS/OFF":Devices.YardLightsPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes("OFF"); responseMsg ="MATI"; urlDitemukan =benar; merusak; case "/DEVICES/YARDLIGHTS/ON":Devices.YardLightsPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes("ON"); responseMsg ="MATI"; urlDitemukan =benar; merusak; case "/DEVICES/POOLSOLAR/OFF":Devices.PoolSolarValvePinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes("OFF"); responseMsg ="MATI"; urlDitemukan =benar; merusak; case "/DEVICES/POOLSOLAR/ON":Devices.PoolSolarValvePinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes("ON"); responseMsg ="ON"; urlDitemukan =benar; merusak; default:bodyArray =Encoding.UTF8.GetBytes(""); urlDitemukan =salah; merusak; } menunggu WriteResponseAsync(request.ToUpper(), responseMsg, urlFound,bodyArray, os); } //Tulis respons untuk metode HTTP yang tidak didukung private async Tugas WriteMethodNotSupportedResponseAsync(permintaan string, IOutputStream os) { bool urlFound =false; byte[] bodyArray =null; bodyArray =Encoding.UTF8.GetBytes(""); menunggu WriteResponseAsync(request.ToUpper(), "TIDAK DIDUKUNG", urlFound, bodyArray, os); } //Tulis respons untuk HTTP GET's dan POST's private async Task WriteResponseAsync(string RequestMsg, string ResponseMsg, bool urlFound, byte[] bodyArray, IOutputStream os) { try //AppService akan mati setelah sekitar satu hari. Mari kita coba menangkapnya secara terpisah sehingga server http akan tetap merespon { var updateMessage =new ValueSet(); updateMessage.Add("Permintaan", RequestMsg); updateMessage.Add("Respon", ResponseMsg); var responseStatus =menunggu appServiceConnection.SendMessageAsync(updateMessage); } catch (Exception) {} try { MemoryStream bodyStream =new MemoryStream(bodyArray); menggunakan (Respons aliran =os.AsStreamForWrite()) { string header =GetHeader(urlFound, bodyStream.Length.ToString()); byte[] headerArray =Encoding.UTF8.GetBytes(header); menunggu respon.WriteAsync(headerArray, 0, headerArray.Length); jika (urlFound) menunggu bodyStream.CopyToAsync(respon); menunggu respon.FlushAsync(); } } catch(Exception) {} } //Membuat teks header HTTP untuk url yang ditemukan dan tidak ditemukan string GetHeader(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" + "Koneksi:tutup\r\n\r\n"; } else { header ="HTTP/1.1 404 Tidak Ditemukan\r\n" + "Access-Control-Allow-Origin:*\r\n" + "Content-Type:text/plain\r\n" + "Content -Panjang:0\r\n" + "Koneksi ditutup\r\n\r\n"; } kembali tajuk; } }}
PoolWebServer - Devices.csC#
Kelas mendefinisikan semua perangkat dan pin GPIO apa yang mereka sambungkan
menggunakan Sistem;menggunakan System.Collections.Generic;menggunakan System.Linq;menggunakan System.Text;menggunakan System.Threading.Tasks;menggunakan Windows.Devices.Gpio; namespace WebServerTask{ //Kelas mendefinisikan semua perangkat dan pin GPIO yang terhubung dengannya. public static class Devices { //Menentukan nomor pin GPIO private const 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; //Menentukan pin GPIO private static GpioPin poolPumpPin; kolam GpioPin statis pribadiWaterfallPin; kolam renang GpioPin statis pribadiLightsPin; halaman GpioPin statis pribadiLightsPin; kumpulan GpioPin statis pribadiSolarValvePin; //Properti untuk GPIO Pin yang ditetapkan ke Pool Pump public static GpioPinValue PoolPumpPinValue { get { return poolPumpPin.Read(); //Baca pin yang dikembalikan Tinggi atau Rendah } set { if (poolPumpPin.Read() !=value) //Hanya setel pin jika mengubah poolPumpPin.Write(value); } } //Property to read status of the Pool Pump ON or OFF public static string PoolPumpState { get { return GetState(PoolPumpPinValue, GpioPinValue.High); //Get the state } } //Property for GPIO Pin assigned to the Waterfall Pump public static GpioPinValue PoolWaterfallPinValue { get { return poolWaterfallPin.Read(); } set { if (poolWaterfallPin.Read() !=value) poolWaterfallPin.Write(value); } } //Property to read status of the Waterfall Pump ON or OFF public static string PoolWaterfallState { get { return GetState(PoolWaterfallPinValue, GpioPinValue.High); } } //Property for GPIO Pin assigned to the Pool Lights public static GpioPinValue PoolLightsPinValue { get { return poolLightsPin.Read(); } set { if (poolLightsPin.Read() !=value) poolLightsPin.Write(value); } } //Property to read status of the Pool Lights ON or OFF public static string PoolLightsState { get { return GetState(PoolLightsPinValue, GpioPinValue.High); } } //Property for GPIO Pin assigned to the valve to turn Solar on and off public static GpioPinValue PoolSolarValvePinValue { get { return poolSolarValvePin.Read(); } set { if (poolSolarValvePin.Read() !=value) poolSolarValvePin.Write(value); } } //Property to read status of the Solar valve ON or OFF public static string PoolSolarValveState { get { return GetState(PoolSolarValvePinValue, GpioPinValue.High); } } //Property for GPIO Pin assigned to the Yard Lights public static GpioPinValue YardLightsPinValue { get { return yardLightsPin.Read(); } set { if (yardLightsPin.Read() !=value) yardLightsPin.Write(value); } } //Property to read status of the Yard Lights ON or OFF public static string YardLightsState { get { return GetState(YardLightsPinValue, GpioPinValue.High); } } //Intialize all GPIO pin used public static void InitDevices() { var gpio =GpioController.GetDefault(); if (gpio !=null) { //These pins are on an active high relay. We set everything to OFF when we start poolPumpPin =gpio.OpenPin(POOL_PUMP_PIN); 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); } } //Gets the state of a device based upon it ActiveState //ActiveState means what required to turn the device on High or Low on the GPIO pin private static string GetState(GpioPinValue value, GpioPinValue ActiveState) { string state ="OFF"; if (value ==ActiveState) state ="ON"; return state; } }}
PoolWebServer - Sensors.csC#
Class that defines all temperature sensors and the I2C interface used to read them
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{ //Class that defines all temperature sensors and the I2C interface used to read them them public static class Sensors { private static I2cDevice Device; private static Timer periodicTimer; //How often to read temperature data from the Arduino Mini Pro private static int ReadInterval =4000; //4000 =4 seconds //Variables to hold temperature data private static string poolTemperature ="--.--"; private static string solarTemperature ="--.--"; private static string outsideTemperature ="--.--"; //Property to expose the Temperature Data public static string PoolTemperature { get { //Lock the variable incase the timer is tring to write to it lock (poolTemperature) { return poolTemperature; } } set { //Lock the variable incase the HTTP Server is tring to read from it lock (poolTemperature) { poolTemperature =value; } } } //Property to expose the Temperature Data public static string SolarTemperature { get { //Lock the variable incase the timer is tring to write to it lock (solarTemperature) { return solarTemperature; } } set { //Lock the variable incase the HTTP Server is tring to read from it lock (solarTemperature) { solarTemperature =value; } } } //Property to expose the Temperature Data public static string OutsideTemperature { get { //Lock the variable incase the timer is tring to write to it lock (outsideTemperature) { return outsideTemperature; } } set { //Lock the variable incase the HTTP Server is tring to read from it lock (outsideTemperature) { outsideTemperature =value; } } } //Initilizes the I2C connection and starts the timer to read I2C Data async public static void InitSensors() { //Set up the I2C connection the Arduino var settings =new I2cConnectionSettings(0x40); // Arduino address settings.BusSpeed =I2cBusSpeed.StandardMode; string aqs =I2cDevice.GetDeviceSelector("I2C1"); var dis =await DeviceInformation.FindAllAsync(aqs); Device =await I2cDevice.FromIdAsync(dis[0].Id, settings); //Create a timer to periodicly read the temps from the Arduino periodicTimer =new Timer(Sensors.TimerCallback, null, 0, ReadInterval); } //Handle the time call back private static void TimerCallback(object state) { byte[] RegAddrBuf =new byte[] { 0x40 }; byte[] ReadBuf =new byte[24]; //Read the I2C connection try { Device.Read(ReadBuf); // read the data } catch (Exception) { } //Parse the response //Data is in the format "88.99|78.12|100.00" where "PoolTemp|SolarTemp|OutsideTemp" char[] cArray =System.Text.Encoding.UTF8.GetString(ReadBuf, 0, 23).ToCharArray(); // Converte Byte to Char String c =new String(cArray).Trim(); string[] data =c.Split('|'); //Write the data to temperature variables try { if (data[0].Trim() !="") PoolTemperature =data[0]; if (data[1].Trim() !="") SolarTemperature =data[1]; if (data[2].Trim() !="") OutsideTemperature =data[2]; } catch (Exception) { } } }}
PoolWebService- MainPage.xaml.csC#
Main page of app that starts the 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{ public sealed partial class MainPage :Page { AppServiceConnection appServiceConnection; public MainPage() { InitializeComponent(); InitializeAppSvc(); } private async void InitializeAppSvc() { string WebServerStatus ="PoolWebServer failed to start. AppServiceConnectionStatus was not successful."; // Initialize the AppServiceConnection appServiceConnection =new AppServiceConnection(); appServiceConnection.PackageFamilyName ="PoolWebServer_hz258y3tkez3a"; appServiceConnection.AppServiceName ="App2AppComService"; // Send a initialize request var res =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 failed to start."; throw new Exception("Failed to send message"); } appServiceConnection.RequestReceived +=OnMessageReceived; WebServerStatus ="PoolWebServer started."; } 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.csC#
// 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;using Windows.Foundation.Collections;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls;using Windows.UI.Xaml.Controls.Primitives;using Windows.UI.Xaml.Data;using Windows.UI.Xaml.Input;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Navigation;namespace PoolWebService{ ///  /// Provides application-specific behavior to supplement the default Application class. ///  sealed partial class App :Application { ///  /// Initializes the singleton application object. This is the first line of authored code /// executed, and as such is the logical equivalent of main() or WinMain(). ///  public App() { InitializeComponent(); Suspending +=OnSuspending; } ///  /// Invoked when the application is launched normally by the end user. Other entry points /// will be used such as when the application is launched to open a specific file. ///  /// Details about the launch request and process. protected override void OnLaunched(LaunchActivatedEventArgs e) {#if DEBUG if (System.Diagnostics.Debugger.IsAttached) { DebugSettings.EnableFrameRateCounter =true; }#endif Frame rootFrame =Window.Current.Content as Frame; // Do not repeat app initialization when the Window already has content, // just ensure that the window is active if (rootFrame ==null) { // Create a Frame to act as the navigation context and navigate to the first page rootFrame =new Frame(); // Set the default language rootFrame.Language =Windows.Globalization.ApplicationLanguages.Languages[0]; rootFrame.NavigationFailed +=OnNavigationFailed; if (e.PreviousExecutionState ==ApplicationExecutionState.Terminated) { //TODO:Load state from previously suspended application } // Place the frame in the current Window Window.Current.Content =rootFrame; } if (rootFrame.Content ==null) { // When the navigation stack isn't restored navigate to the first page, // configuring the new page by passing required information as a navigation // parameter rootFrame.Navigate(typeof(MainPage), e.Arguments); } // Ensure the current window is active Window.Current.Activate(); } ///  /// Invoked when Navigation to a certain page fails ///  /// The Frame which failed navigation /// Details about the navigation failure void OnNavigationFailed(object sender, NavigationFailedEventArgs e) { throw new Exception("Failed to load Page " + e.SourcePageType.FullName); } ///  /// Invoked when application execution is being suspended. Application state is saved /// without knowing whether the application will be terminated or resumed with the contents /// of memory still intact. ///  /// The source of the suspend request. /// Details about the suspend request. private void OnSuspending(object sender, SuspendingEventArgs e) { var deferral =e.SuspendingOperation.GetDeferral(); //TODO:Save application state and stop any background activity deferral.Complete(); } }}
OpenHAB SitemapJavaScript
Sample sitemap used in openHAB configuration
sitemap default label="Windows 10 IoT"{ Frame label="" { Text label="Pool" icon="swimmingpool" { Switch item=PoolPump mappings=[ON="ON", OFF="OFF"] Switch item=WaterFall mappings=[ON="ON", OFF="OFF"] Switch item=PoolLights mappings=[ON="ON", OFF="OFF"] Text item=pooltemp Text item=solartemp Text item=outsidetemp } } }
OpenHAB ItemsPlain text
Sample items openHAB configuration
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"}Switch WaterFall "Water Fall"  (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((.*?))]"}Number outsidetemp "Outside Air Temp [%.2f F]"  (grp1) {http="<[http:///SENSORS/OUTSIDETEMP:30000:REGEX((.*?))]"}
GitHub project repository
Full Visual Studio 2015 Pool Controller projecthttps://github.com/mmackes/Windows-10-IoT-PoolController

Suku cadang dan penutup khusus

Mount to hold DS18B20 waterproof sensor to monitor air temperatureMount to hold DS18B20 waterproof sensor on to standard pool pipingEnclosure for Raspberry Pi and RelaysEnclosure for Raspberry Pi and Relays

Skema

Schematic showing how to connect Raspberry Pi to AC relays. Controls pool pump, waterfall, pool lights and AC yard lights Schematic showing how to connect Raspberry Pi to DC relay. Controls the solar water valve. Schematic showing how to connect Raspberry Pi to Arduino Mini Pro and temperature sensors. Monitors pool water, solar heater water and outside air temperatures.

Proses manufaktur

  1. Pemantauan Suhu di Raspberry Pi
  2. Stasiun Cuaca Raspberry Pi 2
  3. Memantau Suhu Dengan Raspberry Pi
  4. 433MHz Smart Home Controller dengan Sensorflare dan RaspberryPi
  5. Pelacakan Bola Raspberry Pi
  6. Raspberry Pi Universal Remote
  7. Sensor Gerak menggunakan Raspberry Pi
  8. Sepotong Raspberry Pi
  9. Cycle Chaser
  10. Sensor Kelembaban Tanah Raspberry Pi