Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Zwembadcontroller

Componenten en benodigdheden

Raspberry Pi 2 Model B
× 1
PNY 16GB Turbo MicroSDXC CL10
× 1
SparkFun Arduino Pro Mini 328 - 5V/16MHz
× 1
SainSmart 5V 4-kanaals solid-state relaiskaart
× 1
Tolako 5v relaismodule voor Arduino
× 1
DS18b20 waterdichte temperatuursensoren
× 1
4.7k Ohm Weerstanden - 1/4 Watt - 5% - 4K7 (10 stuks)
× 1
Raspberry Pi USB WIFI-dongle
× 1
Een man-naar-vrouw extensie 1-voet USB
× 1
Amerikaanse klep CL40PK6 nummer 40 klem, 6-pack
× 1
J-B Weld 8272 MarineWeld Marine Epoxy - 2 oz
× 1
Zadelring
× 2
Micro USB-voedingsadapter voor wandoplader
× 1

Benodigde gereedschappen en machines

Printrbot Simple
Gebruikt om behuizingen en sensorbevestigingen te maken
Ftdi Usb naar Ttl Seriële Adapter Module voor Arduino Mini Port
Gebruikt om schets te uploaden naar Arduino Mini Pro

Apps en online services

Microsoft Windows 10 IoT Core
Microsoft Visual Studio 2015
Microsoft IIS
Arduino IDE
OneWire-bibliotheek
Dallas Temperature Library
openHAB open source software voor domotica

Over dit project

Geautomatiseerde zwembadcontroller

Twee keer, in drie maanden tijd, deed de timer van mijn zwembadpomp het niet. Dit inspireerde mij tot het maken van dit project. De kosten van het vervangen van die timers waren meer dan $ 120 en alles wat ik moest laten zien was een timer die me heel weinig controle gaf en een hoog percentage mislukkingen. Ik heb ook last gehad van een storing van de temperatuursensor op mijn zonneboiler die $ 30 extra kostte.

Ik wist dat ik een kosteneffectieve geautomatiseerde zwembadcontroller kon maken die me veel meer controle gaf over wanneer mijn zwembadpomp liep. Ik wilde meer variabelen hebben over wanneer de pomp liep in plaats van de eenvoudige tijd en dag van de bestaande timer. Ik wilde ook niet alleen mijn zwembadpomp kunnen automatiseren, maar ook de status van verschillende aspecten van mijn zwembadomgeving kunnen monitoren. Een ander doel was om deze taken overal en met elk apparaat uit te kunnen voeren.

Het project dat ik heb gemaakt is zeer kosteneffectief omdat het gebruik maakt van een Raspberry Pi met Windows 10 IoT Core, relais, Arduino Mini Pro, evenals temperatuursensoren, bedrading en 3D-geprinte componenten. Ik heb dit project voor veel minder geld voltooid dan ik had betaald voor de twee eerdere timers en de zonnetemperatuursensor.

Zwembadpompregeling (AC-componenten)

Ik begon mijn project door solid-state relais te besturen vanaf mijn Raspberry Pi met Windows 10 IoT Core. Met deze relais kan meto mijn AC-componenten (wisselstroom), zoals de zwembadpomp, regelen. De solid-state relais besturen de bestaande 30Amp AC-relais die de oldtimer had gebruikt. Nadat ik het circuit voor de zwembadpomp had ontworpen en getest, heb ik extra functionaliteit gecreëerd om andere AC-componenten te bedienen, zoals mijn zwembadwaterval en mijn zwembad- en tuinverlichting. Met dit gedeelte van het project ontworpen, kon ik al deze elementen op afstand bedienen. Mijn familieleden of ik hoeven niet langer de bedieningskast fysiek te openen om de waterval aan te zetten, de zwembad- of tuinverlichting aan te doen of de timer voor de zwembadpomp in te stellen.

Behuizing zwembadcontroller

Mijn zoon ontwierp de behuizing van de poolcontroller en maakte deze met onze 3D-printer en zorgde ervoor dat zowel de Raspberry Pi als de solid-state relais stevig in de controllerdoos pasten.

Temperatuursensoren

Een van de ontwerpdoelen voor myproject was om naast Dag en Tijd ook besturing mogelijk te maken op basis van variabelen. Ik wilde rekening kunnen houden met de buitentemperatuur, de temperatuur van de zonneboiler en het zwembadwater om te bepalen wanneer de pomp moet draaien en wanneer deze moet werken. Een voorbeeld van wanneer dit type operatie cruciaal zou zijn, is wanneer de buitentemperatuur erg koud is en bijna onder het vriespunt ligt. Als de watertemperatuur van het zwembad ook dicht bij het vriespunt ligt, moet ik ervoor zorgen dat mijn zwembad- en watervalpompen werken om te voorkomen dat leidingen bevriezen en de systemen beschadigen. Met dit project kan ik dit ook bereiken als ik niet thuis ben. Om dit te implementeren heb ik temperatuursensoren in mijn project opgenomen. Ik heb die sensoren gelezen met behulp van een Arduino Mini Pro die die gegevens naar dezelfde Raspberry Pi stuurt die de zwembad- en watervalpompen via de I2C-interface bestuurt.

Buitenluchttemperatuursensor

De buitenluchttemperatuursensor was de eerste sensor die ik integreerde. Nogmaals, mijn zoon ontwierp en printte de sensorbevestiging op onze 3D-printer. Hij probeerde zowel PLA als ABS, ABS werkt eigenlijk beter omdat het weerbestendiger is en een hogere glasovergangstemperatuur heeft waardoor het meer hittebestendig is. Zorg ervoor dat u afdrukt met ten minste 75% vulling. De sensor werd aangesloten zoals hierboven beschreven in het schema.

Watertemperatuursensoren

Ik heb toen de temperatuursensoren van het zwembadwater en de zonneboiler ingebouwd. Dit zou het project in staat stellen om gegevens over de watertemperatuur te verzamelen die aan een gebruiker zouden worden weergegeven en om verdere variabelen te bieden om te bepalen wanneer bepaalde componenten in bedrijf waren of in rust waren. Eerst werd een sensorbevestiging ontworpen en in 3D geprint. Zoals eerder vermeld, werkt ABS eigenlijk beter door betere weers- en hittebestendigheid. Ook zorg ervoor dat u ten minste 75% infill gebruikt .

De watertemperatuursensor bouwen en installeren

Na het afdrukken van de watertemperatuursensorbevestiging, heb ik een verzinkboor gebruikt om een ​​gebied van 45 graden rond het sensorgat te creëren. Hierdoor zou de JB Weld meer oppervlakte hebben om aan te hechten. Ik gebruikte hiervoor liever een boor dan het 3D-printontwerp te veranderen, omdat de ruwe snede van de boor de JB Weld een betere houdkracht leek te geven.

De volgende stap was om de temperatuursensor in de houder te plaatsen totdat deze ongeveer 3/4" uit de onderkant van de houder steekt.  Voeg de zittingring toe om hem op zijn plaats te houden. 

Vul vervolgens de bovenkant van de houder met JB Weld en laat 24 uur drogen.

Na minimaal 24 uur wachten tot de JB Weld droog was, was het tijd om de watertemperatuursensoren te installeren.

BELANGRIJKE opmerking: Zorg ervoor dat alle pompen zijn uitgeschakeld voordat u probeert de watertemperatuursensoren te installeren!

Nadat u ervoor heeft gezorgd dat alle waterpompen zijn uitgeschakeld, is het een goed idee om alle kleppen te openen die de waterdruk kunnen verwijderen uit het gebied waarin u de watertemperatuursensoren installeert. Dit vereenvoudigt de installatie aanzienlijk (en houdt u ook droog).

Boor een gat van 5/16 inch in de leidingen van het zwembad. Installeer de watertemperatuursensor en gebruik 2 klemmen om hem stevig op zijn plaats te houden. Maak niet dezelfde fout als ik heb gedaan en draai de klemmen te vast, te vast aandraaien zal de sensorbevestiging verpletteren. kleppen en zet de pompen aan.  Controleer op lekken.

Klepregeling zonneboiler

Nadat ik de temperatuursensoren had geplaatst, kon ik de klepregeling van de zonneboiler ontwerpen en installeren. De zonneverwarmer gebruikt gelijkspanning in tegenstelling tot de wisselspanning die wordt gebruikt met de andere eerder genoemde zwembadcomponenten. Hiervoor moest ik een DC-relais aansturen in plaats van een AC-relais. Het concept is vergelijkbaar, maar de benodigde relais zijn anders. Zorg ervoor dat de relais die u voor uw project gebruikt, het juiste type spanning regelen dat wordt gebruikt door het apparaat dat u bedient.

Met deze regeling kan ik het zwembadwater naar de zonnepanelen op mijn dak leiden. Ik wil alleen water naar de panelen leiden als de buitenluchttemperatuur boven de 60 graden is. Zodra het water naar de panelen wordt geleid, moet u ervoor zorgen dat het terugstromende water minimaal 2 graden warmer is dan het zwembadwater. Anders is het zonde van de energie om het water naar de panelen te pompen.

De bedrading en aansluitingen van deze besturing zijn te vinden in het schema van de poolcontroller DC Components.

Applicatieontwikkeling

Nadat ik Windows 10IoT Core op mijn Raspberry Pi had geïnstalleerd, realiseerde ik me dat het een ingebouwde webserver heeft die wordt gebruikt om het te beheren. Ik vroeg me af of dit een uitgeklede versie van IIS was? Als dat zo is, zou ik gewoon wat rustgevende diensten op IIS kunnen schrijven en ze voor dit project kunnen bellen. Na veel zoekopdrachten op het web en veel onderzoek, bleek het niet mogelijk te zijn. Die aanpak zou mijn voorkeur hebben, maar het lijkt op dit moment niet haalbaar.

Ik nam een ​​andere benadering en bekeek het voorbeeld "Blinky Web Server" en een artikel over "Druss Blog". Ik besloot een headless Windows 10 IoT Core Background Application te bouwen die fungeert als een eenvoudige HTTP-webserver die reageert op HTTP GET- en POST-verzoeken . 

Binnen een paar dagen had ik een werkend prototype. Dit gaf me veel vertrouwen dat mijn project zou slagen. Dus besloot ik verder te gaan met deze architectuur. Nadat ik mijn code grondig had getest via de debugger van Visual Studio 2015, had ik de indruk dat ik mijn applicatie gemakkelijk kon implementeren.

De toepassing implementeren

Dit is een punt waar ik mee worstelde, dus ik hoop u te laten zien hoe u dergelijke moeilijkheden kunt vermijden. Omdat mijn applicatie grondig was getest in de Visual Studio 2015 debugger, had ik de indruk dat ik de modus gewoon kon veranderen van Debug naar Release om mijn applicatie te implementeren. Ik heb deze aanpak geprobeerd en het heeft mijn applicatie daadwerkelijk geïmplementeerd en gestart in de foutopsporingsmodus. Ik stopte toen met debuggen en probeerde de applicatie uit te voeren vanuit AppX Manager. Ik had geen succes toen ik dit probeerde, ik kreeg alleen een generieke fout die zei:"Toepassing kan niet worden geïnitialiseerd."

De oplossing voor dit probleem is om de huidige implementatie te verwijderen en vervolgens de applicatie te installeren vanuit de AppX Manager. Dit heeft me veel tijd gekost, dus ik hoop dat dit je helpt om dat probleem te voorkomen.

Hoewel de toepassing foutloos liep in de foutopsporingsmodus van Visual Studio 2015, zou deze sterven na ontvangst van het eerste HTTP-verzoek. Ik heb veel tijd besteed aan het oplossen van dit probleem en weet nog steeds niet waarom dit gebeurt.

Omdat ik de druk voelde om dit project af te ronden, besloot ik mijn project te veranderen in het voorbeeld van de "Blinky Web Server". In mijn implementatie zag ik de noodzaak van een Windows 10 IoT Core-schermtoepassing niet omdat ik de webserver had gepland om de GPIO-pinnen te besturen en de I2C-interface te lezen (geen schermtoepassing). Wat ik in mijn project deed, was om de schermtoepassing de webserver te laten starten. De webserver stuurt vervolgens berichten terug naar de schermtoepassing, zodat ik kan zien welke HTTP-oproep door mijn server is ontvangen. Deze aanpak lijkt ijzersterk en het is precies dezelfde code die ik in mijn oorspronkelijke poging heb gebruikt.

Gebruikersinterface

Ten slotte heb ik een HTML-besturingsprogramma gebouwd dat op vrijwel elk apparaat kan worden uitgevoerd. Hierdoor kan ik niet alleen de zwembadpomp, waterval en zwembadverlichting bedienen, maar ook de extra sensoren overal vandaan bewaken.

Later heb ik OpenHAB gebruikt en een sitemap gemaakt die deze extra interface bood.

Ik hoop dat je net zoveel plezier hebt gehad bij het lezen over mijn project als ik bij het maken ervan. Bedankt.

YouTube-, Vimeo- of Vine-link en druk op Enter

Code

  • Arduino Sketch voor temperatuursensoren met I2C
  • PoolWebServer - BackgroundTask.cs
  • PoolWebServer - Devices.cs
  • PoolWebServer - Sensors.cs
  • PoolWebService- MainPage.xaml.cs
  • PoolWebService - App.xaml.cs
  • OpenHAB-sitemap
  • OpenHAB-items
Arduino Sketch voor temperatuursensoren met I2C Java
Code om de DS18b20-temperatuursensoren te lezen en gegevens te verzenden wanneer daarom wordt gevraagd via de I2C-interface.
#include #include #include #define SLAVE_ADDRESS 0x40 //Define GPIO-pin constantsconst int POOL_PIN =3;const int SOLAR_PIN =5;const int OUTSIDE_PIN =7;//Definieer de lengte van onze buffer voor de I2C-interfaceconst int I2C_BUFFER_LEN =24; //BELANGRIJK MAX is 32!!!//Load OneWire - eigen dallas halfgeleidersensorprotocol - geen licentie vereistOneWire poolTemp(POOL_PIN);OneWire solarTemp(SOLAR_PIN);OneWire outsideTemp(OUTSIDE_PIN);//Load Dallas - eigen dallas sensorprotocol dat gebruik maakt van onewire - geen licentie vereistDallasTemperature poolSensor(&poolTemp);DallasTemperature solarSensor(&solarTemp);DallasTemperature outsideSensor(&outsideTemp);//Define I2C bufferchar data[I2C_BUFFER_LEN];String temperatureData;//Definieer variabele voor 1000 timer =0 prelongMilli =s void setup (void) {// Maak verbinding met temperatuursensorbussen poolSensor.begin (); solarSensor.begin(); outsideSensor.begin(); // Start de I2C-interface Wire.begin (SLAVE_ADDRESS); Wire.onRequest(requestEvent);}void loop (void) { // Monitor de tijd om temperatuursensoren eens per gedefinieerd interval te lezen //Lees ze niet sneller dan elke 1 seconde. ze kunnen niet zo snel reageren zonder teken lang currMillis =millis(); if (currMillis - prevMillis> interval) { prevMillis =currMillis; leesTemperaturen(); }}void readTemperatures() {//Lees alle drie de temperatuursensoren poolSensor.requestTemperatures(); solarSensor.requestTemperatures(); outsideSensor.requestTemperatures(); //Sla temperatuurgegevens op in een string //We vullen de volledige lengte van de buffer in om ervoor te zorgen dat oude gegevens worden overschreven //Data heeft de indeling "88.99|78.12|100.00" waarbij "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#
Definieert de HTTP-server die reageert op HTTP POST- en GET-verzoeken
// Copyright (c) Microsoft. Alle rechten voorbehouden.gebruik van System;met behulp van System.Collections.Generic;met behulp van System.Linq;met behulp van System.Text;met behulp van System.Net.Http;met behulp van Windows.Foundation.Collections;met behulp van Windows.ApplicationModel.Background;met behulp van Windows.ApplicationModel. AppService;gebruik van Windows.System.Threading;gebruik van Windows.Networking.Sockets;gebruik van System.IO;gebruik van Windows.Storage.Streams;gebruik van System.Threading.Tasks;gebruik van System.Runtime.InteropServices.WindowsRuntime;gebruik van Windows.Foundation;gebruik van Windows.Devices.Gpio;namespace WebServerTask {openbare verzegelde klasse WebServerBGTask:IBackgroundTask { public void Run (IBackgroundTaskInstance taskInstance) { // Koppel een annuleringshandler aan de achtergrondtaak. taskInstance.Canceled +=OnCanceled; // Haal het uitstelobject op uit de taakinstantie serviceDeferral =taskInstance.GetDeferral(); var appService =taskInstance.TriggerDetails als AppServiceTriggerDetails; if (appService !=null &&appService.Name =="App2AppComService") { appServiceConnection =appService.AppServiceConnection; appServiceConnection.RequestReceived +=OnRequestReceived; } } //Verwerkt berichtverzoeken verzonden vanuit PoolWebService App privé async void OnRequestReceived (AppServiceConnection-afzender, AppServiceRequestReceivedEventArgs args) { var message =args.Request.Message; string command =bericht ["Commando"] als string; switch (commando) { case "Initialize":{ Sensors.InitSensors(); Apparaten.InitDevices(); var messageDeferral =args.GetDeferral(); //Stel een resultaat in om terug te keren naar de beller var returnMessage =new ValueSet(); //Definieer een nieuwe instantie van onze HTTPServer op poort 8888 HttpServer-server =nieuwe HttpServer (8888, appServiceConnection); IAsyncAction asyncAction =Windows.System.Threading.ThreadPool.RunAsync( (workItem) => { //Start de serverserver.StartServer(); }); //Reageer terug naar PoolWebService met een status van succes returnMessage.Add ("Status", "Succes"); var responseStatus =wacht op args.Request.SendResponseAsync(returnMessage); messageDeferral.Complete(); pauze; } case "Quit":{ //Service is gevraagd om te stoppen. Geef ons service-uitstel //zodat het platform de achtergrondtaak kan beëindigen serviceDeferral.Complete(); pauze; } } } private void OnCanceled (IBackgroundTaskInstance afzender, BackgroundTaskCancellationReason reden) {//Opschonen en klaar om af te sluiten} BackgroundTaskDeferral serviceDeferral; AppServiceVerbinding appServiceVerbinding; } //Klasse om de HTTP WebServer openbare verzegelde klasse te definiëren HttpServer:IDisposable {//Maak een buffer om HTTP-gegevens te lezen privé const uint BufferSize =8192; // Poort om te luisteren op privé int-poort =8888; // Luisteraar naar privé alleen-lezen StreamSocketListener-luisteraar; // Verbinding om statusinformatie terug te sturen naar PoolControllerWebService privé AppServiceConnection appServiceConnection; openbare HttpServer (int serverPort, AppServiceConnection-verbinding) { listener =nieuwe StreamSocketListener (); poort =serverpoort; appServiceConnection =verbinding; //Voeg gebeurtenishandler toe voor HTTP-verbindingen listener.ConnectionReceived +=(s, e) => ProcessRequestAsync (e.Socket); } //Bel om de listner public void StartServer() te starten {#pragma warning uitschakelen CS4014 listener.BindServiceNameAsync(port.ToString());#pragma warning restore CS4014 } public void Dispose() { listener.Dispose(); } private async void ProcessRequestAsync (StreamSocket socket) { probeer { StringBuilder request =new StringBuilder (); // Haal de binnenkomende gegevens op met (IInputStream input =socket.InputStream) { byte [] data =new byte [BufferSize]; IBuffer-buffer =data.AsBuffer(); uint dataRead =BufferSize; // Lees alle inkomende gegevens terwijl (dataRead ==BufferSize) {wacht op input.ReadAsync (buffer, BufferSize, InputStreamOptions.Partial); request.Append(Encoding.UTF8.GetString(data, 0, data.Length)); dataRead =buffer.Lengte; } } //Kreeg de gegevens beginnen met het verwerken van een reactie met (IOutputStream output =socket.OutputStream) { string requestMethod =request.ToString(); string [] requestParts ={ "" }; if (requestMethod !=null) { // Verdeel het verzoek in delen requestMethod =requestMethod.Split('\n')[0]; requestParts =requestMethod.Split(' '); } //We reageren alleen op HTTP GETS- en POST-methoden als (requestParts[0] =="GET") wacht op WriteGetResponseAsync(requestParts[1], output); else if (requestParts[0] =="POST") wacht op WritePostResponseAsync(requestParts[1], output); wacht anders op WriteMethodNotSupportedResponseAsync(requestParts[1], output); } } catch (uitzondering) { } } //Behandelt alle HTTP GET's private async Task WriteGetResponseAsync (string request, IOutputStream os) { bool urlFound =false; byte[] bodyArray =null; string responseMsg =""; // Kijk of het verzoek overeenkomt met een van de geldige verzoek-urls en maak de antwoordberichtschakelaar (request.ToUpper()) { case "/SENSORS/POOLTEMP":responseMsg =Sensors.PoolTemperature; urlFound =waar; pauze; case "/SENSORS/SOLARTEMP":responseMsg =Sensors.SolarTemperature; urlFound =waar; pauze; case "/SENSORS/OUTSIDETEMP":responseMsg =Sensors.OutsideTemperature; urlFound =waar; pauze; case "/DEVICES/POOLPUMP/STATE":responseMsg =Devices.PoolPumpState; urlFound =waar; pauze; case "/DEVICES/WATERFALLPUMP/STATE":responseMsg =Devices.PoolWaterfallState; urlFound =waar; pauze; case "/DEVICES/POOLLIGHTS/STATE":responseMsg =Devices.PoolLightsState; urlFound =waar; pauze; case "/DEVICES/YARDLIGHTS/STATE":responseMsg =Devices.YardLightsState; urlFound =waar; pauze; case "/DEVICES/POOLSOLAR/STATE":responseMsg =Devices.PoolSolarValveState; urlFound =waar; pauze; standaard:urlFound =false; pauze; } bodyArray =Encoding.UTF8.GetBytes(responseMsg); wacht WriteResponseAsync(request.ToUpper(), responseMsg, urlFound, bodyArray, os); } //Verwerkt alle privé-async-taken van HTTP POST. WritePostResponseAsync (stringverzoek, IOutputStream os) { bool urlFound =false; byte[] bodyArray =null; string responseMsg =""; // Kijk of het verzoek overeenkomt met een van de geldige verzoek-URL's en maak de antwoordberichtschakelaar (request.ToUpper()) { case "/DEVICES/POOLPUMP/OFF":Devices.PoolPumpPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes("OFF"); responseMsg ="UIT"; urlFound =waar; pauze; case "/DEVICES/POOLPUMP/ON":Devices.PoolPumpPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes("ON"); responseMsg ="AAN"; urlFound =waar; pauze; case "/DEVICES/WATERFALLPUMP/OFF":Devices.PoolWaterfallPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes("OFF"); responseMsg ="UIT"; urlFound =waar; pauze; case "/DEVICES/WATERFALLPUMP/ON":Devices.PoolWaterfallPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes("ON"); responseMsg ="AAN"; urlFound =waar; pauze; geval "/DEVICES/POOLLIGHTS/OFF":Devices.PoolLightsPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes("OFF"); responseMsg ="UIT"; urlFound =waar; pauze; case "/DEVICES/POOLLIGHTS/ON":Devices.PoolLightsPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes("ON"); responseMsg ="UIT"; urlFound =waar; pauze; case "/DEVICES/YARDLIGHTS/OFF":Devices.YardLightsPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes("OFF"); responseMsg ="UIT"; urlFound =waar; pauze; case "/DEVICES/YARDLIGHTS/ON":Devices.YardLightsPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes("ON"); responseMsg ="UIT"; urlFound =waar; pauze; geval "/DEVICES/POOLSOLAR/OFF":Devices.PoolSolarValvePinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes("OFF"); responseMsg ="UIT"; urlFound =waar; pauze; geval "/DEVICES/POOLSOLAR/ON":Devices.PoolSolarValvePinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes("ON"); responseMsg ="AAN"; urlFound =waar; pauze; standaard:bodyArray =Encoding.UTF8.GetBytes(""); urlFound =onwaar; pauze; } wacht WriteResponseAsync(request.ToUpper(), responseMsg, urlFound,bodyArray, os); } // Schrijf het antwoord voor niet-ondersteunde HTTP-methoden private async Taak WriteMethodNotSupportedResponseAsync (string request, IOutputStream os) { bool urlFound =false; byte[] bodyArray =null; bodyArray =Encoding.UTF8.GetBytes(""); wacht WriteResponseAsync(request.ToUpper(), "NOT SUPPORTED", urlFound, bodyArray, os); } // Schrijf het antwoord voor HTTP GET's en POST's private async Taak WriteResponseAsync (string RequestMsg, string ResponseMsg, bool urlFound, byte [] bodyArray, IOutputStream os) {probeer // De appService zal na een dag of zo sterven. Laten we proberen het apart te vangen, zodat de http-server nog steeds reageert { var updateMessage =new ValueSet(); updateMessage.Add("Verzoek", RequestMsg); updateMessage.Add("Response", ResponseMsg); var responseStatus =wacht appServiceConnection.SendMessageAsync(updateMessage); } catch (uitzondering) {} probeer { MemoryStream bodyStream =nieuwe MemoryStream (bodyArray); met behulp van (Stream response =os.AsStreamForWrite()) { string header =GetHeader(urlFound, bodyStream.Length.ToString()); byte[] headerArray =Encoding.UTF8.GetBytes(header); wacht op reactie.WriteAsync(headerArray, 0, headerArray.Length); if (urlFound) wacht op bodyStream.CopyToAsync(response); wacht op reactie.FlushAsync(); } } catch (Exception) {} } // Creëert de HTTP-headertekst voor gevonden en niet gevonden URL's 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" + "Verbinding: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 -Lengte:0\r\n" + "Verbinding sluiten\r\n\r\n"; } retourkoptekst; } }}
PoolWebServer - Devices.csC#
Class the definieert alle apparaten en met welke GPIO-pinnen ze zijn verbonden
met behulp van System;met behulp van System.Collections.Generic;met behulp van System.Linq;met behulp van System.Text;met behulp van System.Threading.Tasks;met behulp van Windows.Devices.Gpio; namespace WebServerTask {//Class de definieert alle apparaten en met welke GPIO-pinnen ze zijn verbonden. openbare statische klasse Apparaten {// Definieer de GPIO-pinnennummers privé const int POOL_PUMP_PIN =12; privé const int POOL_WATERFALL_PIN =13; privé const int POOL_LIGHTS_PIN =16; privé const int YARD_LIGHTS_PIN =18; privé const int POOL_SOLAR_VALVE_PIN =22; // Definieer de GPIO-pinnen privé statische GpioPin poolPumpPin; privé statisch GpioPin zwembadWaterfallPin; privé statisch GpioPin poolLightsPin; privé statische GpioPin yardLightsPin; privé statisch GpioPin poolSolarValvePin; //Eigenschap voor GPIO-pin die is toegewezen aan de openbare statische poolpomp GpioPinValue PoolPumpPinValue { get {return poolPumpPin.Read (); //Lees de pin retourneert Hoog of Laag} set {if (poolPumpPin.Read()!=value) //Stel de pin alleen in als poolPumpPin.Write(value) verandert; } } //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

Aangepaste onderdelen en behuizingen

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

Schema's

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.

Productieproces

  1. Temperatuurbewaking op de Raspberry Pi
  2. Raspberry Pi 2 weerstation
  3. Temperatuur bewaken met Raspberry Pi
  4. 433MHz Smart Home Controller met Sensorflare en een RaspberryPi
  5. Raspberry Pi Ball-tracking
  6. Raspberry Pi universele afstandsbediening
  7. Bewegingssensor met Raspberry Pi
  8. Een stukje Raspberry Pi
  9. Cycle Chaser
  10. Raspberry Pi Bodemvochtsensor
  11. Raspberry Pi diefdetector