Casa rápida Casa inteligente

Os módulos do Master Kit continuam a compartilhar soluções conosco :
“Como um experimento, decidi aqui tentar fazer algum tipo de protótipo de“ casa inteligente ”às pressas e a um custo mínimo. Havia muitos hoteleiros: luz, ventilação, janelas, água e controle infravermelho de aparelhos elétricos. No início, decidi me limitar a um mínimo de tarefas: ventilação e iluminação na sala.



O sistema foi baseado no Arduino Uno, com a capacidade de controlar quatro pinos independentemente um do outro, e vários módulos de controlo sem fios da Master Kit:-canal único e de dois canais MP3328 e MP3330 relés assumiu o papel de dispositivos de execução , e os sinais são transmitidos a eles usando um transmissor de oito canais MP3329 a uma frequência de 433 MHz.





Na MP3330 Eu desliguei o controle de duas tiras de LED sobre o sofá, - uma luz de fundo acolhedor para leitura à noite, - e sobre a MP3328 - o controle de um servo-máquina para abrir / fechar a janela.

Eu construí a estrutura da unidade a partir de materiais improvisados, a partir das partes do designer LEGO.



Bem, e, é claro, o simples controle de rádio não foi suficiente para mim: eu precisava de acesso a todo o sistema por meio de uma interface da web e monitoramento de status em tempo real.

Como recurso de armazenamento, peguei o MySQL padrão, onde criei uma tabela com os identificadores dos controladores, pinos e o valor de status de cada um deles, por questões de segurança, vinculando um identificador de sistema comum a cada um. Além disso, eu habilitei a capacidade de definir um cronômetro fixo para alterar o estado, e também é fornecido um campo para isso.



Ao trabalhar com soquetes da Web, o Arduino estava com um pouco de bugs e, como não havia tempo para descobrir os motivos, desenhei-o de uma maneira simples: com solicitações de ajax a cada 100ms. Obviamente, isso é desastroso para o tráfego (quase 30 MB por dia), mas para um apartamento com Internet ilimitada pela primeira vez, basta.

A interface web mais simples: 4 botões, um para cada pino. Um único toque muda o estado e um toque longo define o temporizador (eu tenho 3 minutos conectados até agora) para alterá-lo.



Como resultado, a versão simplificada da lógica é a seguinte: A

interface da Web acessa o servidor e verifica o status dos controladores, após o qual exibe a interface para trabalhar com o sistema: 4 botões no estado correspondente:

Scripts
$.ajax({
			url: 'engine/ajax.php',
			type: 'POST',
			dataType: 'json',
			data: {action: 'getStates'},
		})
		.done(function(data) {
			for (key in data.success){
				var controller = data.success[key];
				if($('.btn#btn_' + controller.id).length === 0){
					html = '';
					html += '<div ';
					if (controller.timer_switch > 0){
						var seconds = 60  - (controller.timer_switch % 60)
						html += 'seconds="' + seconds + '"';
					}
					html += 'id="btn_' + controller.id + '" class="btn" state="' + controller.state + '"><div class="btn_timer"></div></div>';
					$('#btn_placer').append(html);
				} else {
					if (controller.state == 1){
						$('.btn#btn_' + controller.id).removeClass('btn_off').addClass('btn_on');
					} else if (controller.state == 0){
						$('.btn#btn_' + controller.id).removeClass('btn_on').addClass('btn_off');
					}
					if (controller.timer_switch > 0){
						var seconds = 60 - controller.timer_switch % 60;
						var minutes = Math.floor(controller.timer_switch / 60);
						$('.btn#btn_' + controller.id).addClass('seconds').css('background-position', (-seconds * 100) + 'px 0px').find('.btn_timer').text(minutes + 'M');
					} else {
						$('.btn#btn_' + controller.id).css('background-position', '0px 0px').removeClass('seconds').find('.btn_timer').text('');
					}
				}
			}
			setTimeout(function(){
				getStates();
			}, 1000);
		})
		.fail(function(data) {
			console.log('error');
		});



function getStates($sql){
	$result = $sql->query("SELECT * FROM `controllers` WHERE `home_id` = '1' ORDER BY `order`");
	if (isset($result->rows)){
		$result = $result->rows;
		foreach ($result as $key => $value) {
			if (strtotime($result[$key]['timer']) > -62169990000){
				// echo strtotime($result[$key]['timer']);
				$timer_switch = strtotime($result[$key]['timer']) - strtotime(date("Y-m-d H:i:s"));
				$result[$key]['timer_switch'] = $timer_switch;
				if ($timer_switch < 0){
					$sql->query("UPDATE `controllers` SET `state` = '".$result[$key]['timer_state']."', `timer` = '0000-00-00 00:00:00', `timer_state` = '' WHERE `id` = '".$result[$key]['id']."'");
				}
			}
		}
		$res['success'] = $result;
	} else {
		$res['error'] = ' ';
	}
	return $res;
}




Quando o botão correspondente é pressionado, uma solicitação POST é enviada para o arquivo ajax.php:

Javascript
$(document).on('mousedown', '.btn', function(event){
			event.preventDefault();
			var id = parseInt($(this).attr('id').replace('btn_', ''));
			click_wait = false;
			mousetimer = setTimeout(function(){
				click_wait = true;
				setTimer(id);	
			}, 2000);
		});

		$(document).on('mouseup', '.btn', function(){
			clearTimeout(mousetimer);
			if (!click_wait){
				var id = parseInt($(this).attr('id').replace('btn_', ''));
				switchController(id);
				console.log('click !!!');
				click_wait = false;
			}
		});
	function switchController(id){
		var el = $('.btn#btn_' + id);
		var state = parseInt($(el).attr('state'));
		var need_state;
		if (state == 0){
			need_state = 1;
		} else if (state == 1){
			need_state = 0;
		}
		$(el).addClass('waiting');
		$.ajax({
			url: 'engine/ajax.php',
			type: 'POST',
			dataType: 'json',
			data: {action: 'setState', id: id, state: state, need_state: need_state},
		})
		.done(function(data) {
			if (data.success == 'ok'){
				$(el).attr('state', need_state);
				$(el).removeClass('waiting').removeClass('btn_on').removeClass('btn_off');
				if(need_state == 1){
					$(el).addClass('btn_on');
				} else if(need_state == 0){
					$(el).addClass('btn_off');
				}
			}
		})
		.fail(function(data) {
			console.log('error');
		});
	}
	function setTimer(id){
		var el = $('.btn#btn_' + id);
		var state = parseInt($(el).attr('state'));
		var need_state;
		if (state == 0){
			need_state = 1;
		} else if (state == 1){
			need_state = 0;
		}
		$(el).attr('seconds', 0);
		$(el).addClass('seconds');
		$.ajax({
			url: 'engine/ajax.php',
			type: 'POST',
			dataType: 'json',
			data: {action: 'setTimer', id: id, state: state, need_state: need_state},
		})
		.done(function(data) {
		})
		.fail(function(data) {
			console.log('error');
		});
	}




No ID da variável, passamos o identificador do controlador e, no estado variável, o valor do seu estado. No arquivo ajax.php, obtemos uma solicitação POST e colocamos os novos dados nos valores de registro do ID correspondente.

Php
function setState($sql){
	$need_state = (int)$_POST['need_state'];
	$state = (int)$_POST['state'];
	$id = (int)$_POST['id'];

	$result = $sql->query("UPDATE `controllers` SET `state` = '".$need_state."', `timer` = '0000-00-00 00:00:00' WHERE `id` = '".$id."'");
	//   Arduino
	$result = $sql->query("SELECT `state` FROM `controllers` WHERE `id` = '".$id."'");
	if ($need_state == $result->row['state']){
		$res['success'] = 'ok';
	} else {
		$res['success'] = 'err';
	}
	return $res;
}

function setTimer($sql){
	$need_state = (int)$_POST['need_state'];
	$state = (int)$_POST['state'];
	$id = (int)$_POST['id'];

	$result = $sql->query("UPDATE `controllers` SET `timer` = NOW() + INTERVAL 3 MINUTE, `timer_state` = '".$need_state."' WHERE `id` = '".$id."'");
	//   Arduino
	$result = $sql->query("SELECT `state` FROM `controllers` WHERE `id` = '".$id."'");
	if ($need_state == $result->row['state']){
		$res['success'] = 'ok';
	} else {
		$res['success'] = 'err';
	}
	return $res;
}




O Arduino, por sua vez, acessa o servidor da Web via Ethernet, verifica a chave exclusiva do sistema, os valores do controlador, analisa a string recebida e altera os valores dos pinos.

Php
if (isset($_GET['key']) && $_GET['key'] !== ''){
		$key = $_GET['key'];
	} else {
		die;
	}
	
$key = $sql->escape($key);
	$result = $sql->query("SELECT * FROM `controllers` WHERE `home_id` = '1' AND `key` = '".$key."' ORDER BY `order`");
	foreach ($result->rows as $key => $value) {
		if ($value['id'] == '1'){
			if ($value['state'] == '1'){
				$ar .= 'Q';
			} else if ($value['state'] == '0') {
				$ar .= 'q';
			}
		}
		if ($value['id'] == '2'){
			if ($value['state'] == '1'){
				$ar .= 'W';
			} else if ($value['state'] == '0') {
				$ar .= 'w';
			}
		}
		if ($value['id'] == '3'){
			if ($value['state'] == '1'){
				$ar .= 'E';
			} else if ($value['state'] == '0') {
				$ar .= 'e';
			}
		}
	}




Depois disso, uma linha do formato “% qUerTY” é transferida para um esboço onde é analisada, dependendo das regras de conexão: cada letra corresponde ao seu número de PIN e o registro é responsável pelo valor final: capital - 1, minúscula - 0.

Arduino
void readData(){
  if (led_connect){
    digitalWrite(6, HIGH);
  } else {
    digitalWrite(6, LOW);
  }
  digitalWrite(4, LOW);
  previousMillis = currentMillis;
  
  led_connect = !led_connect;
    while (client.available()){      
      switch (char c = client.read()) {
        case 'Q':
          digitalWrite(9, HIGH);
          break;
        case 'q':
          digitalWrite(9, LOW);
          break;
        case 'W':
          digitalWrite(8, HIGH);
          break;
        case 'w':
          digitalWrite(8, LOW);
          break;
        case 'E':
          digitalWrite(7, HIGH);
          myservo.write(0);
          break;
        case 'e':
          digitalWrite(7, LOW);
          myservo.write(180);
          break;
      }
    }
}



Você pode transferir valores de 0 a 180 (graus de rotação) para o pino responsável pela servomáquina e, por exemplo, para o dimmer - até 255. Ainda tenho dois valores: 0 ou 1.





Não houve problemas ao conectar os módulos: ambos os relés são emparelhados com o transmissor uma vez, sem a necessidade de re-ligação, e executam perfeitamente sua tarefa.





Mas, com o poder da servomáquina, calculei mal um pouco: peguei 6 kg - o que, em geral, é suficiente para cobrir e soltar a caixilharia da janela, que se abriu com seu próprio peso -, mas é melhor usar algo mais poderoso, caso de vento forte ou corrente de ar.

Em geral, o escopo da criatividade é ilimitado: por exemplo, você pode conectar sensores, por exemplo, CO2 ou temperatura, e abrir / fechar a janela quando determinados indicadores forem alcançados.
Bem, é claro, pretendo reescrever todo o sistema em soquetes da Web, facilitando as solicitações - e flexibilizando a transferência e a análise dos valores dos parâmetros.

Esboço para arduino

Vídeo pequeno Luz de

fundo do trabalho


Abertura de janela


Dmitry Kuznetsov "

Source: https://habr.com/ru/post/pt383679/


All Articles