Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Contrôleur de piscine

Composants et fournitures

Raspberry Pi 2 Modèle B
× 1
PNY 16 Go Turbo MicroSDXC CL10
× 1
SparkFun Arduino Pro Mini 328 - 5V/16MHz
× 1
Carte relais statique SainSmart 5V 4 canaux
× 1
Module relais Tolako 5v pour Arduino
× 1
Capteurs de température étanches DS18b20
× 1
Résistances 4,7k Ohm - 1/4 Watt - 5% - 4K7 (10 pièces)
× 1
Dongle WIFI USB Raspberry Pi
× 1
Une extension mâle à femelle 1-pied Usb
× 1
American Valve CL40PK6 Pince numéro 40, paquet de 6
× 1
J-B Weld 8272 MarineWeld Marine Epoxy - 2 oz
× 1
Rondelle de siège
× 2
Adaptateur secteur pour chargeur mural avec alimentation micro USB
× 1

Outils et machines nécessaires

Printrbot Simple
Utilisé pour créer des supports de boîtier et de capteur
Module adaptateur série Ftdi Usb vers Ttl pour mini-port Arduino
Utilisé pour télécharger un croquis sur Arduino Mini Pro

Applications et services en ligne

Microsoft Windows 10 IoT Core
Microsoft Visual Studio 2015
Microsoft IIS
Arduino IDE
Bibliothèque OneWire
Dallas Temperature Library
logiciel domotique open source openHAB

À propos de ce projet

Contrôleur de piscine automatisé

Deux fois, en trois mois, la minuterie de ma pompe de piscine a échoué. Cela m'a inspiré pour créer ce projet. Le coût de remplacement de ces minuteries était de plus de 120 $ et tout ce que j'avais à montrer, c'était une minuterie qui me donnait très peu de contrôle et un taux d'échec élevé. J'ai également subi une panne du capteur de température de mon chauffe-eau solaire qui a coûté 30 $ de plus.

Je savais que je pouvais créer un contrôleur de piscine automatisé rentable qui me donnait beaucoup plus de contrôle sur le moment où ma pompe de piscine fonctionnait. Je voulais avoir plus de variables quant au moment où la pompe fonctionnait au lieu de l'heure et du jour simples de la minuterie existante. Je voulais également pouvoir non seulement automatiser ma pompe de piscine, mais également surveiller l'état de divers aspects de l'environnement de ma piscine. Un autre objectif était de pouvoir accomplir ces tâches de n'importe où en utilisant n'importe quel appareil.

Le projet que j'ai créé est très rentable car il utilise un Raspberry Pi exécutant Windows 10 IoT Core, des relais, Arduino Mini Pro ainsi que des capteurs de température, un câblage et des composants imprimés en 3D. J'ai terminé ce projet pour beaucoup moins d'argent que j'avais payé pour les deux minuteries précédentes et le capteur de température solaire.

Commande de pompe de piscine (composants AC)

J'ai commencé mon projet en contrôlant des relais statiques depuis mon Raspberry Pi sous Windows 10 IoT Core. Ces relais me permettent de contrôler mes composants AC (courant alternatif) tels que la pompe de la piscine. Les relais à semi-conducteurs contrôlent les relais AC 30 A existants que l'ancien temporisateur avait utilisés. Après avoir conçu et testé le circuit de la pompe de piscine, j'ai créé des fonctionnalités supplémentaires pour contrôler d'autres composants AC tels que la cascade de ma piscine et les lumières de ma piscine et de mon jardin. Avec cette partie du projet conçue, je pouvais contrôler tous ces éléments à distance. Les membres de ma famille ou moi n'aurions plus besoin d'ouvrir physiquement le boîtier de commande pour allumer la cascade, allumer les lumières de la piscine ou du jardin ou régler la minuterie de la pompe de la piscine.

Boîtier de contrôleur de piscine

Mon fils a conçu le boîtier du contrôleur de piscine et l'a créé à l'aide de notre imprimante 3D et s'est assuré que le Raspberry Pi et les relais à semi-conducteurs avaient un ajustement sûr dans le boîtier du contrôleur.

Capteurs de température

L'un des objectifs de conception de myproject était de permettre un contrôle basé sur des variables en plus du jour et de l'heure. Je voulais pouvoir prendre en compte la température de l'air extérieur ainsi que les températures du chauffe-eau solaire et de l'eau de la piscine pour déterminer quand la pompe doit fonctionner et quand elle doit être à l'arrêt. Un exemple de cas où ce type d'opération serait crucial est lorsque la température de l'air extérieur est très froide et proche du point de congélation. Si la température de l'eau de la piscine est également proche du point de congélation, je dois m'assurer que les pompes de ma piscine et de ma cascade fonctionnent pour empêcher les tuyaux de geler et d'endommager les systèmes. En utilisant ce projet, je pourrai accomplir cela même lorsque je ne suis pas à la maison. Afin de mettre en œuvre cela, j'ai intégré des capteurs de température dans myproject. J'ai lu ces capteurs utilisant un Arduino Mini Pro qui envoie ces données au même Raspberry Pi qui contrôle les pompes de piscine et de cascade via l'interface I2C.

Capteur de température d'air extérieur

Le capteur de température de l'air extérieur a été le premier capteur que j'ai intégré. Encore une fois, mon fils a conçu et imprimé le support du capteur sur notre imprimante 3D. Il a essayé à la fois le PLA et l'ABS, l'ABS fonctionne en fait mieux car il est plus résistant aux intempéries et a une température de transition vitreuse plus élevée, ce qui le rend plus résistant à la chaleur. Assurez-vous d'imprimer avec au moins 75 % de remplissage. Le capteur a été connecté comme décrit ci-dessus dans le schéma.

Capteurs de température de l'eau

J'ai ensuite intégré les capteurs de température de l'eau de la piscine et du chauffe-eau solaire. Cela permettrait au projet de collecter des données sur la température de l'eau qui seraient affichées pour un utilisateur ainsi que de fournir d'autres variables pour déterminer quand certains composants fonctionnaient ou étaient au repos. Tout d'abord, un support de capteur a été conçu et imprimé en 3D. Comme mentionné précédemment, l'ABS fonctionne mieux en raison d'une meilleure résistance aux intempéries et à la chaleur. De plus, assurez-vous d'utiliser au moins 75 % de remplissage .

Construction et installation du capteur de température de l'eau

Après avoir imprimé le support du capteur de température de l'eau, j'ai utilisé un foret à fraiser pour créer une zone de 45 degrés autour du trou du capteur. Cela permettrait au JB Weld d'avoir plus de surface sur laquelle adhérer. J'ai préféré utiliser un foret pour le faire plutôt que de modifier la conception de l'impression 3D, car la coupe grossière du foret semblait donner au JB Weld une meilleure puissance de maintien.

L'étape suivante consistait à insérer le capteur de température dans le support jusqu'à ce qu'il dépasse d'environ 3/4" du bas du support.  Ajoutez la rondelle de siège pour le maintenir en place. 

Ensuite, remplissez le haut du support avec JB Weld et laissez sécher 24 heures.

Après avoir attendu au moins 24 heures que le JB Weld sèche, il était temps d'installer les capteurs de température d'eau.

Remarque IMPORTANTE : Assurez-vous que toutes les pompes sont éteintes avant d'essayer d'installer les capteurs de température de l'eau !

Après s'être assuré que toutes les pompes à eau sont éteintes, c'est une bonne idée d'ouvrir toutes les vannes qui peuvent supprimer la pression de l'eau de la zone dans laquelle vous installez les capteurs de température de l'eau. Cela facilitera grandement l'installation (et vous gardera également au sec).

Percez un trou de 5/16" dans la tuyauterie de la piscine.  Installez le capteur de température de l'eau et utilisez 2 pinces pour le maintenir fermement en place.  Ne faites pas la même erreur que moi et serrez excessivement les pinces, un serrage excessif écrasera le support du capteur.  Fermer vannes et allumez les pompes.  Vérifiez s'il y a des fuites.

Commande de vanne de chauffage solaire

Après avoir mis en place les capteurs de température, j'ai pu concevoir et installer le contrôle de la vanne du chauffe-eau solaire. Le chauffe-eau solaire utilise une tension continue par opposition aux tensions alternatives utilisées avec les autres composants de la piscine mentionnés précédemment. Cela m'a obligé à contrôler un relais CC au lieu d'un relais CA. Le concept est similaire, mais les relais requis sont différents. Assurez-vous que les relais que vous utilisez pour votre projet contrôlent le type de tension correct utilisé par l'appareil que vous contrôlez.

Ce contrôle me permet de diriger l'eau de la piscine jusqu'aux panneaux solaires sur mon toit. Je veux seulement diriger l'eau vers les panneaux lorsque la température de l'air extérieur est supérieure à 60 degrés. Une fois que l'eau est détournée vers les panneaux, assurez-vous que l'eau de retour est au moins 2 degrés plus chaude que l'eau de la piscine. Sinon, c'est un gaspillage d'énergie de pomper l'eau vers les panneaux.

Le câblage et les connexions de cette commande sont fournis dans le schéma des composants DC du contrôleur de piscine.

Développement d'applications

Après avoir installé Windows 10IoT Core sur mon Raspberry Pi, j'ai réalisé qu'il avait un serveur Web intégré qui est utilisé pour le gérer. Je me demandais s'il s'agissait d'une version allégée d'IIS ? Si c'est le cas, je pourrais simplement écrire des services reposants sur IIS et les appeler pour ce projet. Après de nombreuses recherches sur le Web et de nombreuses recherches, cela ne semblait pas possible. Cette approche serait celle que je préférerais, mais elle ne semble pas faisable pour le moment.

Adoptant une approche différente, j'ai examiné l'exemple "Blinky Web Server" et un article sur "Druss Blog". J'ai décidé de créer une application d'arrière-plan Windows 10 IoT Core sans tête qui agit comme un simple serveur Web HTTP répondant aux requêtes HTTP GET et POST. . 

En quelques jours, j'avais un prototype fonctionnel. Cela m'a donné beaucoup de confiance que mon projet pourrait être couronné de succès. J'ai donc décidé d'aller de l'avant avec cette architecture. Après avoir minutieusement testé mon code via le débogueur Visual Studio 2015, j'avais l'impression que je pouvais facilement déployer mon application.

Déploiement de l'application

C'est un point avec lequel j'ai lutté, alors j'espère vous montrer comment éviter une telle difficulté. Parce que mon application a été soigneusement testée dans le débogueur Visual Studio 2015, j'avais l'impression que je pouvais simplement changer le mode de Debug à Release pour déployer mon application. J'ai essayé cette approche et elle a en fait déployé mon application et l'a démarrée en mode débogage. J'ai ensuite arrêté le débogage et tenté d'exécuter l'application à partir d'AppX Manager. Je n'ai eu aucun succès lorsque j'ai essayé cela, j'obtiendrais simplement une erreur générique indiquant :« L'application n'a pas pu s'initialiser. »

La solution à ce problème consiste à supprimer le déploiement actuel, puis à installer l'application à partir du gestionnaire AppX à la place. Cela m'a coûté beaucoup de temps, alors j'espère que cela vous aidera à éviter ce problème.

Même si l'application fonctionnait parfaitement en mode de débogage Visual Studio 2015, elle mourrait après avoir reçu la première requête HTTP. J'ai passé beaucoup de temps à essayer de résoudre ce problème et je ne sais toujours pas pourquoi cela se produit.

Sentant la pression de terminer ce projet, j'ai décidé de changer mon projet pour qu'il ressemble à l'exemple de « Blinky Web Server ». Dans mon implémentation, je n'ai pas vu le besoin d'une application d'écran Windows 10 IoT Core car j'avais prévu que le serveur Web contrôle les broches GPIO et lise l'interface I2C (pas une application d'écran). Ce que j'ai fait dans mon projet, c'est que l'application écran démarre le serveur Web. Le serveur Web renvoie ensuite des messages à l'application écran afin que je puisse voir quel appel HTTP a été reçu par mon serveur. Cette approche semble être solide et c'est exactement le même code que j'ai utilisé dans ma tentative initiale.

Interface utilisateur

Enfin, j'ai construit un programme de contrôle HTML qui s'exécutera sur pratiquement n'importe quel appareil. Cela me permet non seulement de contrôler la pompe de la piscine, la cascade et les lumières de la piscine, mais également de surveiller les capteurs supplémentaires de n'importe où.

Plus tard, j'ai utilisé OpenHAB et créé un plan du site qui m'a donné cette interface supplémentaire.

J'espère que vous avez pris autant de plaisir à lire sur mon projet que j'en ai pris à le créer. Merci.

Lien YouTube, Vimeo ou Vine, et appuyez sur Entrée

Code

  • Arduino Sketch pour capteurs de température utilisant I2C
  • PoolWebServer - BackgroundTask.cs
  • PoolWebServer - Devices.cs
  • PoolWebServer - Sensors.cs
  • PoolWebService - MainPage.xaml.cs
  • PoolWebService - App.xaml.cs
  • Plan du site OpenHAB
  • Objets OpenHAB
Arduino Sketch pour capteurs de température utilisant I2C Java
Code pour lire les capteurs de température DS18b20 et envoyer des données sur demande via l'interface I2C.
#include #include #include #define SLAVE_ADDRESS 0x40 //Définir la broche GPIO constantsconst int POOL_PIN =3;const int SOLAR_PIN =5;const int OUTSIDE_PIN =7;//Définir la longueur de notre buffer pour l'interface I2Cconst int I2C_BUFFER_LEN =24; //IMPORTANT MAX est de 32 !!! //Load OneWire - protocole propriétaire de capteur à semi-conducteur dallas - aucune licence requiseOneWire poolTemp(POOL_PIN);OneWire solarTemp(SOLAR_PIN);OneWire outsideTemp(OUTSIDE_PIN);//Load Dallas - protocole propriétaire de capteur dallas utilisant onewire - aucune licence requiseDallasTemperature poolSensor(&poolTemp);DallasTemperature solarSensor(&solarTemp);DallasTemperature outsideSensor(&outsideTemp);//Define I2C bufferchar data[I2C_BUFFER_LEN];String temperatureData;//Define variable for timerlong;long prevMillis intervals =1000; void setup(void) { //Se connecter aux bus du capteur de température poolSensor.begin(); solarSensor.begin(); outsideSensor.begin(); //Démarrer l'interface I2C Wire.begin(SLAVE_ADDRESS); Wire.onRequest(requestEvent);}void loop(void) { //Le temps de surveillance pour lire les capteurs de température une fois par intervalle défini //Ne les lisez pas plus vite que toutes les 1 seconde. ils ne peuvent pas répondre aussi rapidement et sans signe currMillis =millis(); if (currMillis - prevMillis> intervalle) { prevMillis =currMillis; readTemperatures(); }}void readTemperatures() { //Lire les trois capteurs de température poolSensor.requestTemperatures(); solarSensor.requestTemperatures(); outsideSensor.requestTemperatures(); //Stocker les données de température dans une chaîne //Nous remplissons toute la longueur du tampon pour nous assurer d'écraser les anciennes données //Les données sont au format "88.99|78.12|100.00" où "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#
Définit le serveur HTTP qui répond aux requêtes HTTP POST et GET
// Copyright (c) Microsoft. Tous droits réservés.utilisation de System;utilisation de System.Collections.Generic;utilisation de System.Linq;utilisation de System.Text;utilisation de System.Net.Http;utilisation de Windows.Foundation.Collections;utilisation de Windows.ApplicationModel.Background;utilisation de Windows.ApplicationModel. AppService;utilisation de Windows.System.Threading;utilisation de Windows.Networking.Sockets;utilisation de System.IO;utilisation de Windows.Storage.Streams;utilisation de System.Threading.Tasks;utilisation de System.Runtime.InteropServices.WindowsRuntime;utilisation de Windows.Foundation;utilisation Windows.Devices.Gpio;namespace WebServerTask{ public scellé classe WebServerBGTask :IBackgroundTask { public void Run(IBackgroundTaskInstance taskInstance) { // Associe un gestionnaire d'annulation à la tâche en arrière-plan. taskInstance.Canceled +=OnCanceled ; // Récupère l'objet de report de l'instance de tâche serviceDeferral =taskInstance.GetDeferral(); var appService =taskInstance.TriggerDetails as AppServiceTriggerDetails ; if (appService !=null &&appService.Name =="App2AppComService") { appServiceConnection =appService.AppServiceConnection; appServiceConnection.RequestReceived +=OnRequestReceived ; } } //Traite les demandes de messages envoyées depuis PoolWebService App privé asynchrone void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) { var message =args.Request.Message; chaîne commande =message["Commande"] en tant que chaîne ; switch (commande) { case "Initialize":{ Sensors.InitSensors(); Devices.InitDevices(); var messageDeferral =args.GetDeferral(); //Définir un résultat à renvoyer à l'appelant var returnMessage =new ValueSet(); //Définir une nouvelle instance de notre HTTPServer sur le port 8888 HttpServer server =new HttpServer(8888, appServiceConnection); IAsyncAction asyncAction =Windows.System.Threading.ThreadPool.RunAsync( (workItem) => { //Démarrer le serveur Server.StartServer(); }); //Répondre à PoolWebService avec un statut de réussite returnMessage.Add("Status", "Success"); var responseStatus =wait args.Request.SendResponseAsync(returnMessage); messageDeferral.Complete(); Pause; } case "Quitter":{ //Le service a été invité à quitter. Donnez-nous un report de service //pour que la plate-forme puisse terminer la tâche d'arrière-plan serviceDeferral.Complete(); Pause; } } } private void OnCanceled (expéditeur IBackgroundTaskInstance, raison BackgroundTaskCancellationReason) { // Nettoyer et se préparer à quitter } BackgroundTaskDeferral serviceDeferral; AppServiceConnection appServiceConnection; } //Classe pour définir la classe scellée publique HTTP WebServer HttpServer :IDisposable { //Créer un tampon pour lire les données HTTP private const uint BufferSize =8192; //Port à écouter sur le port int privé =8888; //Listener to private readonly StreamSocketListener listener; //Connexion pour renvoyer les informations d'état à PoolControllerWebService private AppServiceConnection appServiceConnection; public HttpServer(int serverPort, connexion AppServiceConnection) { listener =new StreamSocketListener(); port =port du serveur ; appServiceConnection =connexion ; //Ajouter un gestionnaire d'événements pour les connexions HTTP listener.ConnectionReceived +=(s, e) => ProcessRequestAsync(e.Socket); } //Appel pour démarrer le listner public void StartServer() {#pragma warning disable CS4014 listener.BindServiceNameAsync(port.ToString());#pragma warning restore CS4014 } public void Dispose() { listener.Dispose(); } privé asynchrone void ProcessRequestAsync(StreamSocket socket) { try { StringBuilder request =new StringBuilder(); //Obtenir les données entrantes en utilisant (IInputStream input =socket.InputStream) { byte[] data =new byte[BufferSize]; IBuffer buffer =data.AsBuffer(); uint dataRead =BufferSize; //Lire toutes les données entrantes while (dataRead ==BufferSize) { wait input.ReadAsync(buffer, BufferSize, InputStreamOptions.Partial); request.Append(Encoding.UTF8.GetString(data, 0, data.Length)); dataRead =buffer.Length; } } //Les données commencent à traiter une réponse en utilisant (IOutputStream output =socket.OutputStream) { string requestMethod =request.ToString(); string[] requestParts ={ "" } ; if (requestMethod !=null) { // Beakup la requête dans ses parties requestMethod =requestMethod.Split('\n')[0]; requestParts =requestMethod.Split(' '); } //Nous ne répondons aux méthodes HTTP GETS et POST que si (requestParts[0] =="GET") wait WriteGetResponseAsync(requestParts[1], output); else if (requestParts[0] =="POST") wait WritePostResponseAsync(requestParts[1], output); else wait WriteMethodNotSupportedResponseAsync(requestParts[1], sortie); } } catch (Exception) { } } // Gère toutes les tâches asynchrones privées de HTTP GET WriteGetResponseAsync (demande de chaîne, IOutputStream os) { bool urlFound =false; octet[] bodyArray =null; string responseMsg ="" ; //Vérifiez si la requête correspond à l'une des URL de requêtes valides et créez le commutateur de message de réponse (request.ToUpper()) { case "/SENSORS/POOLTEMP":responseMsg =Sensors.PoolTemperature; urlTrouvé =vrai ; Pause; case "/SENSORS/SOLARTEMP":responseMsg =Sensors.SolarTemperature; urlTrouvé =vrai ; Pause; case "/SENSORS/OUTSIDETEMP":responseMsg =Sensors.OutsideTemperature; urlTrouvé =vrai ; Pause; case "/DEVICES/POOLPUMP/STATE":responseMsg =Devices.PoolPumpState; urlTrouvé =vrai ; Pause; case "/DEVICES/WATERFALLPUMP/STATE":responseMsg =Devices.PoolWaterfallState; urlTrouvé =vrai ; Pause; case "/DEVICES/POOLLIGHTS/STATE":responseMsg =Devices.PoolLightsState; urlTrouvé =vrai ; Pause; case "/DEVICES/YARDLIGHTS/STATE":responseMsg =Devices.YardLightsState; urlTrouvé =vrai ; Pause; case "/DEVICES/POOLSOLAR/STATE":responseMsg =Devices.PoolSolarValveState; urlTrouvé =vrai ; Pause; par défaut :urlFound =false; Pause; } bodyArray =Encoding.UTF8.GetBytes(responseMsg); wait WriteResponseAsync(request.ToUpper(), responseMsg, urlFound, bodyArray, os); } // Gère toutes les tâches asynchrones privées de HTTP POST WritePostResponseAsync (demande de chaîne, IOutputStream os) { bool urlFound =false; octet[] bodyArray =null; string responseMsg ="" ; //Vérifiez si la requête correspond à l'une des URL de requêtes valides et créez le commutateur de message de réponse (request.ToUpper()) { case "/DEVICES/POOLPUMP/OFF":Devices.PoolPumpPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes("OFF"); réponseMsg ="OFF" ; urlTrouvé =vrai ; Pause; case "/DEVICES/POOLPUMP/ON":Devices.PoolPumpPinValue =GpioPinValue.High ; bodyArray =Encoding.UTF8.GetBytes("ON"); réponseMsg ="ON" ; urlTrouvé =vrai ; Pause; case "/DEVICES/WATERFALLPUMP/OFF":Devices.PoolWaterfallPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes("OFF"); réponseMsg ="OFF" ; urlTrouvé =vrai ; Pause; case "/DEVICES/WATERFALLPUMP/ON":Devices.PoolWaterfallPinValue =GpioPinValue.High ; bodyArray =Encoding.UTF8.GetBytes("ON"); réponseMsg ="ON" ; urlTrouvé =vrai ; Pause; case "/DEVICES/POOLLIGHTS/OFF":Devices.PoolLightsPinValue =GpioPinValue.Low ; bodyArray =Encoding.UTF8.GetBytes("OFF"); réponseMsg ="OFF" ; urlTrouvé =vrai ; Pause; case "/DEVICES/POOLLIGHTS/ON":Devices.PoolLightsPinValue =GpioPinValue.High ; bodyArray =Encoding.UTF8.GetBytes("ON"); réponseMsg ="OFF" ; urlTrouvé =vrai ; Pause; case "/DEVICES/YARDLIGHTS/OFF":Devices.YardLightsPinValue =GpioPinValue.Low ; bodyArray =Encoding.UTF8.GetBytes("OFF"); réponseMsg ="OFF" ; urlTrouvé =vrai ; Pause; case "/DEVICES/YARDLIGHTS/ON":Devices.YardLightsPinValue =GpioPinValue.High ; bodyArray =Encoding.UTF8.GetBytes("ON"); réponseMsg ="OFF" ; urlTrouvé =vrai ; Pause; case "/DEVICES/POOLSOLAR/OFF":Devices.PoolSolarValvePinValue =GpioPinValue.Low ; bodyArray =Encoding.UTF8.GetBytes("OFF"); réponseMsg ="OFF" ; urlTrouvé =vrai ; Pause; case "/DEVICES/POOLSOLAR/ON":Devices.PoolSolarValvePinValue =GpioPinValue.High ; bodyArray =Encoding.UTF8.GetBytes("ON"); réponseMsg ="ON" ; urlTrouvé =vrai ; Pause; par défaut :bodyArray =Encoding.UTF8.GetBytes(""); urlFound =false; Pause; } wait WriteResponseAsync(request.ToUpper(), responseMsg, urlFound,bodyArray, os); } //Écrire la réponse pour les méthodes HTTP non prises en charge private async Task WriteMethodNotSupportedResponseAsync (string request, IOutputStream os) { bool urlFound =false; octet[] bodyArray =null; bodyArray =Encoding.UTF8.GetBytes(""); wait WriteResponseAsync(request.ToUpper(), "NON PRIS EN CHARGE", urlFound, bodyArray, os); } //Écrivez la réponse pour la tâche asynchrone privée de HTTP GET et POST WriteResponseAsync(string RequestMsg, string ResponseMsg, bool urlFound, byte[] bodyArray, IOutputStream os) { try //L'appService mourra après environ un jour. Essayons de le récupérer séparément afin que le serveur http réponde toujours { var updateMessage =new ValueSet(); updateMessage.Add("Request", RequestMsg); updateMessage.Add("Réponse", ResponseMsg); var responseStatus =wait 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); wait response.WriteAsync(headerArray, 0, headerArray.Length); if (urlFound) wait bodyStream.CopyToAsync(response); attendre la réponse.FlushAsync(); } } catch(Exception) {} } //Crée le texte d'en-tête HTTP pour les URL trouvées et introuvables 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" + "Connexion :fermer\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 -Longueur : 0\r\n" + "Connexion fermée\r\n\r\n" ; } retourner l'en-tête ; } }}
PoolWebServer - Devices.csC#
La classe définit tous les périphériques et les broches GPIO auxquelles ils sont connectésà l'aide de System ;à l'aide de System.Collections.Generic ;à l'aide de System.Linq ;à l'aide de System.Text ;à l'aide de System.Threading.Tasks ;à l'aide de Windows.Devices.Gpio ; namespace WebServerTask{ //Class the définit tous les périphériques et les broches GPIO auxquelles ils sont connectés. public static class Devices { //Définir les numéros de broches GPIO private const int POOL_PUMP_PIN =12; privé const int POOL_WATERFALL_PIN =13 ; const privé entier POOL_LIGHTS_PIN =16 ; privé const int YARD_LIGHTS_PIN =18 ; const privé entier POOL_SOLAR_VALVE_PIN =22 ; //Définir les broches GPIO private static GpioPin poolPumpPin; pool GpioPin statique privéWaterfallPin; poolLightsPin GpioPin statique privé ; GpioPin statique privé yardLightsPin ; pool GpioPin statique privéSolarValvePin ; //Propriété de la broche GPIO affectée à la pompe de piscine public static GpioPinValue PoolPumpPinValue { get { return poolPumpPin.Read(); //Lire la broche renvoie High ou Low } set { if (poolPumpPin.Read() !=value) //Ne définir la broche que si est en train de changer 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

Pièces et boîtiers personnalisés

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

Schémas

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.

Processus de fabrication

  1. Surveillance de la température sur le Raspberry Pi
  2. Station météo Raspberry Pi 2
  3. Contrôle de la température avec Raspberry Pi
  4. Contrôleur Smart Home 433MHz avec Sensorflare et RaspberryPi
  5. Suivi de la boule Raspberry Pi
  6. Télécommande universelle Raspberry Pi
  7. Capteur de mouvement utilisant Raspberry Pi
  8. Une tranche de framboise Pi
  9. Cycle Chaser