Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Manufacturing Technology >> Processo de manufatura

Controlador de piscina

Componentes e suprimentos

Raspberry Pi 2 Modelo B
× 1
PNY 16GB Turbo MicroSDXC CL10
× 1
SparkFun Arduino Pro Mini 328 - 5 V / 16 MHz
× 1
SainSmart 5V Placa de relé de estado sólido de 4 canais
× 1
Módulo de relé Tolako 5v para Arduino
× 1
DS18b20 Sensores de temperatura à prova d'água
× 1
Resistores de 4,7 k Ohm - 1/4 Watt - 5% - 4K7 (10 peças)
× 1
Raspberry Pi USB WIFI Dongle
× 1
Um macho para fêmea extensão USB de 1 pé
× 1
Válvula americana CL40PK6 Braçadeira número 40, pacote de 6
× 1
J-B Weld 8272 MarineWeld Marine Epoxy - 2 oz
× 1
Arruela de assento
× 2
Adaptador CA para carregador de parede com fonte de alimentação micro USB
× 1

Ferramentas e máquinas necessárias

Printrbot Simple
Usado para criar gabinetes e montagens de sensor
Ftdi Usb para Módulo Adaptador Serial Ttl para Arduino Mini Port
Usado para fazer upload do esboço para o Arduino Mini Pro

Aplicativos e serviços online

Microsoft Windows 10 IoT Core
Microsoft Visual Studio 2015
Microsoft IIS
Arduino IDE
Biblioteca OneWire
Biblioteca de temperatura de Dallas
software de automação residencial openHAB

Sobre este projeto





Controlador de piscina automatizado


Duas vezes, em três meses, o cronômetro da minha bomba de piscina falhou. Isso me inspirou a criar este projeto. O custo de substituição desses cronômetros era de mais de US $ 120 e tudo o que eu tinha a mostrar era um cronômetro que me dava muito pouco controle e uma alta taxa de falha. Também sofri uma falha no sensor de temperatura do meu aquecedor solar de água que custou US $ 30 adicionais.

Eu sabia que poderia criar um controlador de pool automatizado de baixo custo que me desse muito mais controle sobre quando minha bomba de pool funcionava. Eu queria ter mais variáveis ​​sobre quando a bomba funcionou, em vez da hora e dia simples do cronômetro existente. Eu também queria ser capaz de não apenas automatizar minha bomba de piscina, mas também monitorar o status de vários aspectos do ambiente da minha piscina. Um outro objetivo era ser capaz de realizar essas tarefas de qualquer lugar usando qualquer dispositivo.

O projeto que criei é muito econômico, pois utiliza um Raspberry Pi executando o Windows 10 IoT Core, Relays, Arduino Mini Pro, bem como sensores de temperatura, fiação e componentes impressos em 3D. Concluí este projeto por muito menos dinheiro do que paguei pelos dois cronômetros anteriores e pelo sensor de temperatura solar.





Controle da bomba da piscina (componentes AC)


Comecei meu projeto controlando relés de estado sólido do meu Raspberry Pi executando o Windows 10 IoT Core. Esses relés me permitem controlar meus componentes AC (corrente alternada), como a bomba da piscina. Os relés de estado sólido controlam os relés 30Amp AC existentes que o temporizador antigo utilizava. Depois de projetar e testar o circuito da bomba da piscina, criei uma funcionalidade adicional para controlar outros componentes de CA, como a cachoeira da piscina e as luzes da piscina e do quintal. Com esta parte do projeto desenhada, eu poderia controlar todos esses elementos remotamente. Meus familiares ou eu não precisariam mais abrir fisicamente a caixa de controle para ligar a cachoeira, ligar as luzes da piscina ou do quintal ou definir o cronômetro para a bomba da piscina.





Gabinete do controlador da piscina


Meu filho projetou o gabinete do Pool Controller e o criou usando nossa impressora 3D e garantiu que tanto o Raspberry Pi quanto os relés de estado sólido se encaixassem com segurança na caixa do controlador.





Sensores de temperatura


Um dos objetivos do design do meu projeto era permitir o controle com base em variáveis ​​além do dia e da hora. Eu queria ser capaz de levar em consideração a temperatura externa, bem como as temperaturas do aquecedor solar de água e da água da piscina, para determinar quando a bomba deveria funcionar e quando deveria ser testada. Um exemplo de quando esse tipo de operação seria crucial é quando a temperatura do ar externo é muito baixa e quase congelante. Se a temperatura da água da piscina também estiver perto de congelar, preciso garantir que as bombas da piscina e da cascata estejam funcionando para evitar que os canos congelem e danifiquem os sistemas. Usando este projeto, poderei realizar isso mesmo quando não estiver em casa. Para implementar isso, incorporei sensores de temperatura em meu projeto. Eu li esses sensores utilizando um Arduino Mini Pro que envia os dados para o mesmo Raspberry Pi que controla as bombas da piscina e da cachoeira por meio da interface I2C.





Sensor de temperatura do ar externo


O sensor de temperatura do ar externo foi o primeiro sensor que incorporei. Novamente, meu filho projetou e imprimiu a montagem do sensor em nossa impressora 3D. Ele experimentou o PLA e o ABS, o ABS funciona melhor porque é mais resistente às intempéries e tem uma temperatura de transição vítrea mais alta, tornando-o mais resistente ao calor. Certifique-se de imprimir com pelo menos 75% de preenchimento. O sensor foi conectado conforme descrito acima no esquema.





Sensores de temperatura da água


Em seguida, incorporei os sensores de temperatura da água da piscina e do aquecedor solar. Isso permitiria ao projeto coletar dados de temperatura da água que seriam exibidos a um usuário, bem como fornecer outras variáveis ​​para determinar quando certos componentes funcionaram ou estavam em repouso. Primeiro, uma montagem de sensor foi projetada e impressa em 3D. Conforme mencionado anteriormente, o ABS funciona melhor devido à melhor resistência ao clima e ao calor. Além disso, certifique-se de usar pelo menos 75% de preenchimento .





Construção e instalação do sensor de temperatura da água


Depois de imprimir a montagem do sensor de temperatura da água, usei uma broca escareada para criar uma área de 45 graus ao redor do orifício do sensor. Isso permitiria que a solda JB tivesse mais área de superfície para aderir. Eu preferi usar uma broca para fazer isso em vez de alterar o design de impressão 3D, pois o corte bruto da broca parecia dar ao JB Weld melhor poder de retenção.

A próxima etapa foi inserir o sensor de temperatura na montagem até que se estenda cerca de 3/4 "da parte inferior da montagem. Adicione a arruela de assento para prendê-la no lugar.

Em seguida, preencha o topo da montagem com JB Weld e deixe secar por 24 horas.

Depois de esperar pelo menos 24 horas para que o JB Weld seque, era hora de instalar os sensores de temperatura da água.

Nota IMPORTANTE: Certifique-se de que todas as bombas estão desligadas antes de tentar instalar os sensores de temperatura da água!

Depois de verificar se todas as bombas d'água estão desligadas, é uma boa ideia abrir todas as válvulas que possam remover a pressão da água da área em que você está instalando os sensores de temperatura da água. Isso facilitará muito a instalação (e também o manterá seco).

Faça um orifício de 5/16 "na tubulação da piscina. Instale o sensor de temperatura da água e utilize 2 braçadeiras para prendê-lo firmemente no lugar. Não cometa o mesmo erro que cometi e aperte demais as braçadeiras, o aperto excessivo esmagará a montagem do sensor. Fechar válvulas e ligue as bombas. Verifique se há vazamentos.





Controle da válvula do aquecedor solar


Depois de colocar os sensores de temperatura no lugar, eu poderia projetar e instalar o controle da válvula do aquecedor solar de água. O Aquecedor Solar utiliza voltagem DC em oposição às voltagens AC usadas com os outros componentes da piscina mencionados anteriormente. Isso exigia que eu controlasse um relé DC em vez de um relé AC. O conceito é semelhante, mas os relés necessários são diferentes. Certifique-se de que os relés usados ​​em seu projeto controlem o tipo correto de voltagem usado pelo dispositivo que você está controlando.

Este controle me permite direcionar a água da piscina até os painéis solares no meu telhado. Eu só quero direcionar a água para os painéis quando a temperatura do ar externo estiver acima de 60 graus. Assim que a água for desviada para os painéis, certifique-se de que a água que retorna está pelo menos 2 graus mais quente do que a água da piscina. Caso contrário, é um desperdício de energia bombear a água para os painéis.

A fiação e as conexões deste controle são fornecidas no esquema de Componentes CC do Controlador de Pool.





Desenvolvimento de aplicativos


Depois de instalar o Windows 10IoT Core em meu Raspberry Pi, percebi que ele possui um servidor da web integrado que é usado para gerenciá-lo. Gostaria de saber se esta era uma versão simplificada do IIS? Nesse caso, eu poderia simplesmente escrever alguns serviços repousantes no IIS e chamá-los para este projeto. Depois de muitas pesquisas na web e muita pesquisa, não parecia ser possível. Eu preferiria essa abordagem, mas não parece viável neste momento.

Adotando uma abordagem diferente, analisei o exemplo ”Blinky Web Server" e um artigo no ”Druss Blog”. Decidi construir um aplicativo de fundo IoT Core do Windows 10 sem cabeça que atua como um servidor da Web HTTP simples respondendo a solicitações HTTP GET e POST .

Em alguns dias, eu tinha um protótipo funcionando. Isso me deu muita confiança de que meu projeto poderia ser bem-sucedido. Então decidi seguir em frente com essa arquitetura. Depois de testar exaustivamente meu código por meio do depurador do Visual Studio 2015, tive a impressão de que poderia facilmente implantar meu aplicativo.





Implementando o aplicativo


Este é um ponto com o qual tenho lutado, então espero mostrar a você como evitar tal dificuldade. Como meu aplicativo foi totalmente testado no depurador do Visual Studio 2015, tive a impressão de que poderia apenas alterar o modo de depuração para liberação para implantar meu aplicativo. Eu tentei essa abordagem e ela de fato implantou meu aplicativo e o iniciou no modo de depuração. Em seguida, parei a depuração e tentei executar o aplicativo a partir do AppX Manager. Não tive sucesso quando tentei fazer isso, eu apenas recebia um erro genérico que dizia:"O aplicativo falhou ao inicializar."

A solução para esse problema é excluir a implantação atual e, em vez disso, instalar o aplicativo do AppX Manager. Isso me custou muito tempo, então espero que ajude você a evitar esse problema.

Mesmo que o aplicativo tenha executado perfeitamente no modo de depuração do Visual Studio 2015, ele morreria após receber a primeira solicitação HTTP. Passei muito tempo tentando solucionar isso e ainda não sei por que isso ocorre.

Sentindo pressão para concluir este projeto, decidi mudar meu projeto para ficar igual ao exemplo do “Blinky Web Server”. Em minha implementação, não vi a necessidade de um aplicativo de tela do Windows 10 IoT Core devido ao fato de que planejei que o servidor web controlasse os pinos GPIO e lesse a interface I2C (não um aplicativo de tela). O que fiz no meu projeto foi fazer com que o aplicativo de tela iniciasse o servidor web. O servidor da Web então envia mensagens de volta para o aplicativo de tela para que eu possa ver qual chamada HTTP foi recebida pelo meu servidor. Esta abordagem parece ser sólida como uma rocha e é exatamente o mesmo código que usei na minha tentativa original.





Interface do usuário


Por fim, desenvolvi um programa de controle de HTML que pode ser executado virtualmente em qualquer dispositivo. Isso me permite não apenas controlar a bomba da piscina, a cachoeira e as luzes da piscina, mas também monitorar os sensores adicionais de qualquer lugar.

Mais tarde, usei o OpenHAB e criei um mapa do site que forneceu essa interface adicional.

Espero que você tenha gostado de ler sobre meu projeto tanto quanto eu gostei de criá-lo. Obrigado.

Link do YouTube, Vimeo ou Vine e pressione Enter

Código

  • Arduino Sketch para sensores de temperatura usando I2C
  • PoolWebServer - BackgroundTask.cs
  • PoolWebServer - Devices.cs
  • PoolWebServer - Sensors.cs
  • PoolWebService- MainPage.xaml.cs
  • PoolWebService - App.xaml.cs
  • Mapa do site OpenHAB
  • Itens OpenHAB
Arduino Sketch para sensores de temperatura usando I2C Java
Código para ler os sensores de temperatura DS18b20 e enviar dados quando solicitados pela interface I2C.
 #include  #include  #include  #define SLAVE_ADDRESS 0x40 // Definir pino GPIO constantsconst int POOL_PIN =3; const int SOLAR_PIN =5; const int OUTSIDE_PIN =7; // Definir o comprimento de nosso buffer para a interface I2C int I2C_BUFFER_LEN =24; // IMPORTANTE MAX é 32 !!! // Carregar OneWire - protocolo de sensor de semicondutor dallas proprietário - nenhuma licença necessáriaOneWire poolTemp (POOL_PIN); OneWire solarTemp (SOLAR_PIN); OneWire outsideTemp (OUTSIDE_PIN); // Carregar Dallas - protocolo de sensor de dallas proprietário utilizando onewire - nenhuma licença necessáriaDallasTemperature poolSensor (&poolTemp); DallasTemperature solarSensor (&solarTemp); DallasTemperature outsideSensor (&outsideTemp); // Definir dados do buffer I2C [I2C_BUFFER_LEN]; String temperatureData; // Definir intervalo de tempo para timerlong prevMillis =0; void setup (void) {// Conectar aos barramentos do sensor de temperatura poolSensor.begin (); solarSensor.begin (); outsideSensor.begin (); // Inicie a interface I2C Wire.begin (SLAVE_ADDRESS); Wire.onRequest (requestEvent);} void loop (void) {// Monitore o tempo para ler os sensores de temperatura uma vez a cada intervalo definido // Não os leia mais rápido do que a cada 1 segundo. eles não podem responder tão rápido sem sinal longo currMillis =millis (); if (currMillis - prevMillis> intervalo) {prevMillis =currMillis; readTemperatures (); }} void readTemperatures () {// Lê todos os três sensores de temperatura poolSensor.requestTemperatures (); solarSensor.requestTemperatures (); outsideSensor.requestTemperatures (); // Armazena os dados de temperatura em uma string // Preenchemos todo o comprimento do buffer para ter certeza de sobrescrever os dados antigos // Os dados estão no formato "88,99 | 78,12 | 100,00" onde "PoolTemp | SolarTemp | OutsideTemp" temperatureData =padRight (String (poolSensor.getTempFByIndex (0)) + "|" + String (solarSensor.getTempFByIndex (0)) + "|" + String (outsideSensor.getTempFByIndex (0)), I2C_BUFFER_LEN);} String padRight (String em , int inLen) {while (inStr.length ()  
PoolWebServer - BackgroundTask.cs C #
Define o servidor HTTP que responde às solicitações HTTP POST e GET
 // Copyright (c) Microsoft. Todos os direitos reservados. Usando System; usando System.Collections.Generic; usando System.Linq; usando System.Text; usando System.Net.Http; usando Windows.Foundation.Collections; usando Windows.ApplicationModel.Background; usando Windows.ApplicationModel. AppService; usando Windows.System.Threading; usando Windows.Networking.Sockets; usando System.IO; usando Windows.Storage.Streams; usando System.Threading.Tasks; usando System.Runtime.InteropServices.WindowsRuntime; usando Windows.Foundation; usando Windows.Devices.Gpio; namespace WebServerTask {classe selada pública WebServerBGTask:IBackgroundTask {public void Run (IBackgroundTaskInstance taskInstance) {// Associar um manipulador de cancelamento à tarefa em segundo plano. taskInstance.Canceled + =OnCanceled; // Obtenha o objeto de adiamento da instância da tarefa serviceDeferral =taskInstance.GetDeferral (); var appService =taskInstance.TriggerDetails as AppServiceTriggerDetails; if (appService! =null &&appService.Name =="App2AppComService") {appServiceConnection =appService.AppServiceConnection; appServiceConnection.RequestReceived + =OnRequestReceived; }} // Processa solicitações de mensagem enviadas do aplicativo PoolWebService private async void OnRequestReceived (AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) {var message =args.Request.Message; string command =mensagem ["Command"] como string; switch (comando) {case "Initialize":{Sensors.InitSensors (); Devices.InitDevices (); var messageDeferral =args.GetDeferral (); // Defina um resultado para retornar ao chamador var returnMessage =new ValueSet (); // Definir uma nova instância do nosso HTTPServer na porta 8888 HttpServer server =new HttpServer (8888, appServiceConnection); IAsyncAction asyncAction =Windows.System.Threading.ThreadPool.RunAsync ((workItem) => {// Iniciar o servidor de servidor.StartServer ();}); // Responder a PoolWebService com um Status de Sucesso returnMessage.Add ("Status", "Sucesso"); var responseStatus =await args.Request.SendResponseAsync (returnMessage); messageDeferral.Complete (); pausa; } case "Quit":{// O serviço foi solicitado a encerrar. Dê-nos o adiamento do serviço // para que a plataforma possa encerrar a tarefa em segundo plano serviceDeferral.Complete (); pausa; }}} private void OnCanceled (IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) {// Limpe e prepare-se para sair} BackgroundTaskDeferral serviceDeferral; AppServiceConnection appServiceConnection; } // Classe para definir a classe pública selada do HTTP WebServer HttpServer:IDisposable {// Criar um buffer para ler dados HTTP private const uint BufferSize =8192; // Porta para escutar em private int port =8888; // Ouvinte para ouvinte privado somente leitura StreamSocketListener; // Conexão para enviar informações de status de volta para PoolControllerWebService private AppServiceConnection appServiceConnection; HttpServer público (int serverPort, conexão AppServiceConnection) {listener =new StreamSocketListener (); port =serverPort; appServiceConnection =conexão; // Adicionar manipulador de eventos para listener de conexões HTTP.ConnectionReceived + =(s, e) => ProcessRequestAsync (e.Socket); } // Chamada para iniciar o listner public void StartServer () {#pragma aviso desabilitar CS4014 listener.BindServiceNameAsync (port.ToString ()); # pragma aviso restaurar CS4014} public void Dispose () {listener.Dispose (); } private assíncrono void ProcessRequestAsync (StreamSocket socket) {try {StringBuilder request =new StringBuilder (); // Obtenha os dados de entrada usando (IInputStream input =socket.InputStream) {byte [] data =new byte [BufferSize]; Buffer IBuffer =data.AsBuffer (); uint dataRead =BufferSize; // Lê todos os dados de entrada while (dataRead ==BufferSize) {await input.ReadAsync (buffer, BufferSize, InputStreamOptions.Partial); request.Append (Encoding.UTF8.GetString (data, 0, data.Length)); dataRead =buffer.Length; }} // Os dados começam a processar uma resposta usando (IOutputStream output =socket.OutputStream) {string requestMethod =request.ToString (); string [] requestParts ={""}; if (requestMethod! =null) {// Beakup da solicitação em suas partes requestMethod =requestMethod.Split ('\ n') [0]; requestParts =requestMethod.Split (''); } // Só respondemos métodos HTTP GETS e POST se (requestParts [0] =="GET") esperar WriteGetResponseAsync (requestParts [1], saída); else if (requestParts [0] =="POST") espera WritePostResponseAsync (requestParts [1], saída); outra espera WriteMethodNotSupportedResponseAsync (requestParts [1], saída); }} catch (Exception) {}} // Lida com todos os HTTP GET's assíncronos Task WriteGetResponseAsync (string request, IOutputStream os) {bool urlFound =false; byte [] bodyArray =null; string responseMsg =""; // Veja se a solicitação corresponde a algum dos urls de solicitação válidos e crie a troca de mensagem de resposta (request.ToUpper ()) {case "/ SENSORS / POOLTEMP":responseMsg =Sensors.PoolTemperature; urlFound =true; pausa; case "/ SENSORS / SOLARTEMP":responseMsg =Sensors.SolarTemperature; urlFound =true; pausa; case "/ SENSORS / OUTSIDETEMP":responseMsg =Sensors.OutsideTemperature; urlFound =true; pausa; case "/ DEVICES / POOLPUMP / STATE":responseMsg =Devices.PoolPumpState; urlFound =true; pausa; case "/ DEVICES / WATERFALLPUMP / STATE":responseMsg =Devices.PoolWaterfallState; urlFound =true; pausa; case "/ DEVICES / POOLLIGHTS / STATE":responseMsg =Devices.PoolLightsState; urlFound =true; pausa; case "/ DEVICES / YARDLIGHTS / STATE":responseMsg =Devices.YardLightsState; urlFound =true; pausa; case "/ DEVICES / POOLSOLAR / STATE":responseMsg =Devices.PoolSolarValveState; urlFound =true; pausa; padrão:urlFound =false; pausa; } bodyArray =Encoding.UTF8.GetBytes (responseMsg); esperar WriteResponseAsync (request.ToUpper (), responseMsg, urlFound, bodyArray, os); } // Lida com todas as tarefas assíncronas privadas de HTTP POST WritePostResponseAsync (solicitação de string, IOutputStream os) {bool urlFound =false; byte [] bodyArray =null; string responseMsg =""; // Veja se a solicitação corresponde a qualquer um dos urls de solicitações válidas e crie a troca de mensagem de resposta (request.ToUpper ()) {case "/ DEVICES / POOLPUMP / OFF":Devices.PoolPumpPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes ("OFF"); responseMsg ="OFF"; urlFound =true; pausa; case "/ DEVICES / POOLPUMP / ON":Devices.PoolPumpPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes ("ON"); responseMsg ="ON"; urlFound =true; pausa; case "/ DEVICES / WATERFALLPUMP / OFF":Devices.PoolWaterfallPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes ("OFF"); responseMsg ="OFF"; urlFound =true; pausa; case "/ DEVICES / WATERFALLPUMP / ON":Devices.PoolWaterfallPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes ("ON"); responseMsg ="ON"; urlFound =true; pausa; case "/ DEVICES / POOLLIGHTS / OFF":Devices.PoolLightsPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes ("OFF"); responseMsg ="OFF"; urlFound =true; pausa; case "/ DEVICES / POOLLIGHTS / ON":Devices.PoolLightsPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes ("ON"); responseMsg ="OFF"; urlFound =true; pausa; case "/ DEVICES / YARDLIGHTS / OFF":Devices.YardLightsPinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes ("OFF"); responseMsg ="OFF"; urlFound =true; pausa; case "/ DEVICES / YARDLIGHTS / ON":Devices.YardLightsPinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes ("ON"); responseMsg ="OFF"; urlFound =true; pausa; case "/ DEVICES / POOLSOLAR / OFF":Devices.PoolSolarValvePinValue =GpioPinValue.Low; bodyArray =Encoding.UTF8.GetBytes ("OFF"); responseMsg ="OFF"; urlFound =true; pausa; case "/ DEVICES / POOLSOLAR / ON":Devices.PoolSolarValvePinValue =GpioPinValue.High; bodyArray =Encoding.UTF8.GetBytes ("ON"); responseMsg ="ON"; urlFound =true; pausa; padrão:bodyArray =Encoding.UTF8.GetBytes (""); urlFound =false; pausa; } esperar WriteResponseAsync (request.ToUpper (), responseMsg, urlFound, bodyArray, os); } // Grava a resposta para métodos HTTP não suportados private async Tarefa WriteMethodNotSupportedResponseAsync (string request, IOutputStream os) {bool urlFound =false; byte [] bodyArray =null; bodyArray =Encoding.UTF8.GetBytes (""); esperar WriteResponseAsync (request.ToUpper (), "NOT SUPPORTED", urlFound, bodyArray, os); } // Escreva a resposta para HTTP GETs e POST's assíncronos Tarefa WriteResponseAsync (string RequestMsg, string ResponseMsg, bool urlFound, byte [] bodyArray, IOutputStream os) {try // O appService morrerá após um dia ou mais. Vamos tentar capturá-lo separadamente para que o servidor http ainda responda {var updateMessage =new ValueSet (); updateMessage.Add ("Request", RequestMsg); updateMessage.Add ("Resposta", ResponseMsg); var responseStatus =await appServiceConnection.SendMessageAsync (updateMessage); } catch (Exception) {} try {MemoryStream bodyStream =new MemoryStream (bodyArray); using (Stream response =os.AsStreamForWrite ()) {string header =GetHeader (urlFound, bodyStream.Length.ToString ()); byte [] headerArray =Encoding.UTF8.GetBytes (cabeçalho); aguardar resposta.WriteAsync (headerArray, 0, headerArray.Length); if (urlFound) espera bodyStream.CopyToAsync (resposta); aguardar resposta.FlushAsync (); }} catch (Exception) {}} // Cria o texto do cabeçalho HTTP para urls encontrados e não encontrados 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" + " Comprimento do conteúdo:"+ bodyStreamLength +" \ r \ n "+" Conexão:fechar \ 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" + "Conteúdo -Comprimento:0 \ r \ n "+" Conexão fechada \ r \ n \ r \ n "; } cabeçalho de retorno; }}} 
PoolWebServer - Devices.cs C #
Class o define todos os dispositivos e quais pinos GPIO eles estão conectados a
 usando System; usando System.Collections.Generic; usando System.Linq; usando System.Text; usando System.Threading.Tasks; usando Windows.Devices.Gpio; namespace WebServerTask {// A classe define todos os dispositivos e a quais pinos GPIO eles estão conectados. public static class Devices {// Definir os números dos pinos GPIO private const int POOL_PUMP_PIN =12; privado const int POOL_WATERFALL_PIN =13; const privado int POOL_LIGHTS_PIN =16; const privado int YARD_LIGHTS_PIN =18; private const int POOL_SOLAR_VALVE_PIN =22; // Define os pinos GPIO private static GpioPin poolPumpPin; private static GpioPin poolWaterfallPin; private static GpioPin poolLightsPin; GpioPin estático privado yardLightsPin; poolSolarValvePin estático privado de GpioPin; // Propriedade para GPIO Pin atribuída à Bomba de Pool public static GpioPinValue PoolPumpPinValue {get {return poolPumpPin.Read (); // Ler o pino retorna alto ou baixo} set {if (poolPumpPin.Read ()! =Value) // Só define o pino se estiver mudando 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

Peças personalizadas e gabinetes

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

Esquemas

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.

Processo de manufatura

  1. Monitoramento de temperatura no Raspberry Pi
  2. Estação meteorológica Raspberry Pi 2
  3. Monitorando a temperatura com Raspberry Pi
  4. Controlador Smart Home de 433 MHz com Sensorflare e RaspberryPi
  5. Rastreamento Raspberry Pi Ball
  6. Controle remoto universal Raspberry Pi
  7. Sensor de movimento usando Raspberry Pi
  8. Uma fatia de Raspberry Pi
  9. Cycle Chaser
  10. Sensor de umidade do solo Raspberry Pi