快速家居智能家居

Master Kit模块继续与我们共享解决方案
“作为一项实验,我决定在这里尝试着急着以最低的成本制作某种“智能家居”原型。有很多旅馆经营者:灯光,通风,窗户,水和电器的红外控制。起初,我决定将自己的工作限制在最低限度:房间的通风和照明。



该系统基于Arduino Uno,能够彼此独立地控制四个引脚,并且来自Master Kit的多个无线控制模块:单通道和两通道MP3328MP3330继电器担当执行设备的角色,并且信号通过八通道发送器发送给它们MP3329,频率为433 MHz。





在MP3330上,我将沙发上的两个LED灯条的控制挂了起来-一个舒适的背光供晚上看书,-在MP3328上,我将控制伺服电机的开/关窗口。

我用即兴的材料(即乐高设计师的零件)构建了驱动器结构。



好吧,当然,简单的无线电控制对我来说还不够:我需要通过Web界面和实时状态监视来访问整个系统。

作为存储资源,我采用了标准的MySQL,在其中创建了一个表,其中包含控制器,引脚和它们各自的状态值的标识符,出于安全目的,它们将公共系统标识符绑定到每个控制器。此外,我还设置了固定计时器以更改状态的功能,并且为此提供了一个字段。



当使用Web套接字时,Arduino有点漏洞,并且没有时间弄清楚原因,因此,我以一种简单的方式来绘制草图:每100毫秒执行一次ajax请求。当然,这对于流量来说是灾难性的(每天将近30MB),但是对于第一次没有互联网限制的公寓,这就足够了。

最简单的Web界面:4个按钮,每个针脚一个。只需按一下即可更改状态,长按可以设置计时器(到目前为止,我有3分钟的接线时间)可以更改状态。



结果,该逻辑的简化版本如下:

Web界面访问服务器并检查控制器的状态,此后它显示用于系统工作的界面:4个处于相应状态的按钮:

剧本
$.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;
}




当按下相应的按钮时,POST请求将发送到ajax.php文件:

Java脚本
$(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');
		});
	}




在变量id中,我们传递控制器的标识符,在变量状态中,传递其状态的值。在ajax.php文件中,我们获得一个POST请求,并将新数据放入相应ID的记录值中。

p
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;
}




Arduino随后通过以太网访问Web服务器,检查唯一的系统密钥,控制器值,解析接收到的字符串并切换引脚值。

p
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';
			}
		}
	}




此后,根据硬接线规则,将一行“%qUerTY”形式的行转移到一个草图,在该草图中对其进行解析:每个字母对应于其引脚号,并且寄存器负责最终值:大写-1,小写-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;
      }
    }
}



您可以将值从0到180(旋转度)传输到负责伺服机的销,例如到调光器-最多255.我仍然有两个值:0或1.





连接模块没有问题:两者继电器与发送器配对一次,无需重新绑定,可以完美地执行其任务。





但是,由于伺服电机的功能,我做了一些错误的计算:我拿了6公斤-通常来说,这足以覆盖并放开窗框,而窗框是在自重的作用下打开的-但最好是用一些更大的力大风或吃水的情况。

通常,创造力的范围是无限的:例如,您可以连接传感器(例如CO2或温度),并在达到某些指标时打开/关闭窗口。
好吧,当然,我计划在Web套接字上重写整个系统,使请求更轻松-并使参数值的传输和解析更加灵活。

arduino

小视频

工作背光图


开窗


德米特里·库兹涅佐夫

Source: https://habr.com/ru/post/zh-CN383679/


All Articles