where(["key"=>"light_state_switch"])->value("val"); if(!$switch || $switch == "on"){ // 先关闭 $switchCmdStr = jsonCmdStr("LIGHT_STATE_SWITCH", ["state" => "off"]); $socket = sendSocketMsg($switchCmdStr, 0, 1, "LIGHT_STATE_SWITCH"); $socketStatus = returnCmdDeal($socket, $switchCmdStr, function ($code,$msg) { writeLog("关闭网关设备信息上报失败,错误码:".$code."-错误消息:".$msg); }); } // 修复zone的日程表 $zoneList = sqlite("zones")->field("id,zone_title,holidays")->select(); foreach ($zoneList as $zone){ if (!$zone["holidays"]) continue; $holidaysList = json_decode($zone["holidays"], true); foreach ($holidaysList as $k => $v){ // 开始修复 $params = []; $params[] = replenStr(dechex($v["table_id"]), 4, 1); $start = $v["num"]; if ($start >= 38) { // 特殊日 $startDate = explode("-", $v["start_time"]); $params[] = $startDate[2] . $startDate[1]; } else { $startDate = explode("-", $v["start_time"]); $endDate = explode("-", $v["end_time"]); $params[] = $startDate[2] . $startDate[1]; $params[] = $endDate[2] . $endDate[1]; } $loc = replenStr(dechex($start), 2); $socket = writeACTCmd(dechex($zone["id"] + 20480), $loc, "01", $params, "76"); $socketStatus = returnCmdDeal($socket["result"], $socket["cmdStr"], function($code,$msg) use($zone) { writeLog("重写Zone:".$zone["zone_title"]."的日程失败,错误码:".$code."-错误消息:".$msg); }); } } // 修复传感器群组的日程表 $groupList = sqlite("groups")->field("id,group_title,holidays")->where(["type"=>["in",[3,4,5,6,8,9,12,13,14]]])->select(); foreach ($groupList as $group){ if (!$group["holidays"]) continue; $holidaysList = json_decode($group["holidays"], true); $gwid = sqlite("group_device")->where(["gid"=>$group["id"]])->value("gwid"); if(!$gwid){ writeLog("传感器群组:".$group["group_title"]."未找到网关id"); continue; } $ip = sqlite("gateways")->where(["id"=>$gwid])->value("eth_ip"); if(!$ip){ writeLog("传感器群组:".$group["group_title"]."未找到对应的网关IP"); continue; } foreach ($holidaysList as $k => $v){ // 开始修复 $params = []; $params[] = replenStr(dechex($v["table_id"]), 4, 1); $start = $v["num"]; if ($start >= 38) { // 特殊日 $startDate = explode("-", $v["start_time"]); $params[] = $startDate[2] . $startDate[1]; } else { $startDate = explode("-", $v["start_time"]); $endDate = explode("-", $v["end_time"]); $params[] = $startDate[2] . $startDate[1]; $params[] = $endDate[2] . $endDate[1]; } $loc = replenStr(dechex($start), 2); $cmdStr = jsonCmdStr("SET_SENSOR_PERIOD", ["addr" => dechex($group["id"]), "byte7" => $loc, "byte8"=>"01", "ip"=>$ip, "param"=>implode("", $params)]); $res = sendSocketMsg($cmdStr, 0, 1, "SET_SENSOR_PERIOD"); $socketStatus = returnCmdDeal($res, $cmdStr, function ($code,$msg) use ($group){ writeLog("重写传感器群组:".$group["group_title"]."的日程失败,错误码:".$code."-错误消息:".$msg); }); } } if(!$switch || $switch == "on"){ // 原来是打开的重新打开 $switchCmdStr = jsonCmdStr("LIGHT_STATE_SWITCH", ["state" => "on"]); $socket = sendSocketMsg($switchCmdStr, 0, 1, "LIGHT_STATE_SWITCH"); $socketStatus = returnCmdDeal($socket, $switchCmdStr, function ($code,$msg) { writeLog("打开网关设备信息上报失败,错误码:".$code."-错误消息:".$msg); }); } // 写入动作/配置等 function writeACTCmd($addr="",$byte7,$byte8,$data=[], $byte4="71"){ if(!$addr || !$byte7 || !$byte8) return false; $addr = swapHilo($addr); $serial = getSerial(); $byte = []; $byte[0] = "E0"; $byte[1] = $serial[0]; $byte[2] = $serial[1]; $byte[3] = $serial[2]; $byte[4] = $byte4; $byte[5] = $addr["lbyte"]; $byte[6] = $addr["hbyte"]; $byte[7] = $byte7; $byte[8] = $byte8; if(!empty($data)){ foreach ($data as $k => $v) { $byte[9+$k] = $v; } } $cmdStr = implode("",$byte); $crc = crc16($cmdStr); $cmdStr .= $crc; $result = sendSocketMsg($cmdStr); if(!$result){ } return ["cmdStr"=>$cmdStr,"result"=>$result]; } function sendSocketMsg($data,$hex=1,$back=1, $cmd=""){ $host = "127.0.0.1"; $port = "2347"; $socket = socket_create(AF_INET,SOCK_STREAM,0); if ($socket < 0) return false; $result = @socket_connect($socket,$host,$port); if (!$result)return false; // 转成二级制流发送 if(is_array($data)){ // 是数组,批量发送 foreach ($data as $k => $v) { if($hex) $v = hex2bin(preg_replace("# #", "", $v)); socket_write($socket,$v,strlen($v)); } }else{ if($hex) $data = hex2bin(preg_replace("# #", "", $data)); $res = socket_write($socket,$data,strlen($data)); } if($back!=0){ do{ $is_fail = false; $input = socket_read($socket, 1024); $is = json_decode($input, true); if($is && $cmd && $is["cmd"] != $cmd && $is["cmd"] != "GLOBAL"){ $is_fail = true; }else if(strpos($input, $cmd)){ break; } }while($is_fail); // $input = bin2hex($input); // 将2进制数据转换成16进制 socket_close ($socket); return $input; }else{ socket_close ($socket); return true; } } function crc16($str) { $string = pack("H*", $str); $crc = 0xFFFF; for ($x = 0; $x < strlen($string); $x++) { $crc = $crc ^ ord($string[$x]); for ($y = 0; $y < 8; $y++) { if (($crc & 0x0001) == 0x0001) { $crc = (($crc >> 1) ^ 0xA001); } else { $crc = $crc >> 1; } } } return crcSwapHilo($crc); } function crcSwapHilo($crc) { $hbyte = dechex(floor($crc / 256)); $lbyte = dechex($crc % 256); if (strlen($hbyte) <= 1) $hbyte = "0" . $hbyte; if (strlen($lbyte) <= 1) $lbyte = "0" . $lbyte; return $lbyte . $hbyte; } function returnCmdDeal($returnCmd,$cmdStr, $failCall=null, $successCall=null){ if(!$returnCmd){ call_user_func($failCall, "00", ""); return false; } /* * 过滤粘包 * 防止出现:{"code":"00","cmd":"","data":[]}{"code":"01","cmd":"","data":[]} */ if(!preg_match("/(\{.*\}\})/", $returnCmd, $matches) && !preg_match("/(\{.*\})/", $returnCmd, $matches)) return false; $data = json_decode($matches[1],true); if(is_null($data)){ $successCall && call_user_func($successCall, true); return true; } if($data["cmd"] == "75"){ $is = call_user_func($failCall, "00", "操作失败,网关ip:".$data["data"]); if($is === false) return false; } if($data["code"] == "40"){ // 网关不在线 $is = call_user_func($failCall, $data["code"], "网关不在线"); if($is === false) return false; }elseif($data["code"] == "0a"){ // 设备不在线 $is = call_user_func($failCall, $data["code"], "设备不在线"); if($is === false) return false; }elseif($data["code"] == "07") { $is = call_user_func($failCall, $data["code"], "设备超时"); if($is === false) return false; }elseif($data["code"] == "08") { $is = call_user_func($failCall, $data["code"], "未设置meshId和密码"); if($is === false) return false; }elseif($data["code"] == "09") { $is = call_user_func($failCall, $data["code"], "设备类型错误"); if($is === false) return false; }elseif($data["code"] == "13") { $is = call_user_func($failCall, $data["code"], "操作无效,系统正在升级中"); if($is === false) return false; }elseif($data["code"] == "02") { $is = call_user_func($failCall, $data["code"], "设备地址错误"); if($is === false) return false; }elseif($data["code"] == "-1") { $is = call_user_func($failCall, $data["code"], "失败"); if($is === false) return false; }elseif($data["code"] == "-2") { $is = call_user_func($failCall, $data["code"], "自动备份中,请勿操作"); if($is === false) return false; }elseif($data["code"] == "-3") { $is = call_user_func($failCall, $data["code"], "预设导入中,请误操作"); if($is === false) return false; }elseif($data["code"] == "-4") { $is = call_user_func($failCall, $data["code"], "正在恢复数据中,请误操作"); if($is === false) return false; }elseif($data["code"] == "-5") { $is = call_user_func($failCall, $data["code"], "系统很拥挤"); if($is === false) return false; }elseif($data["code"] == "-6") { $is = call_user_func($failCall, $data["code"], "mcu正在matching"); if($is === false) return false; }elseif($data["code"] == "03") { $is = call_user_func($failCall, $data["code"], "数据地址错误"); if($is === false) return false; }elseif($data["code"] == "05") { $is = call_user_func($failCall, $data["code"], "数据超出范围"); if($is === false) return false; }elseif($data["code"] == "04") { $is = call_user_func($failCall, $data["code"], "数据长度错误"); if($is === false) return false; }elseif($data["code"] == "0d") { $is = call_user_func($failCall, $data["code"], "mcu忙碌着"); if($is === false) return false; }elseif($data["code"] == "00"){ if(empty($data["data"])) { $successCall && call_user_func($successCall, true); return true; } else { $successCall &&call_user_func($successCall, $data["data"]); return $data["data"]; } }elseif($data["code"] == "0b"){ $is = call_user_func($failCall, $data["code"], "当前网关设备地址254个已用完"); if($is === false) return false; }elseif($data["code"] == "01"){// 需要重发,重发次数5 $count = 4; while ($count > 0) { $socket = sendSocketMsg($cmdStr); if(strcasecmp($socket,"FAD20001")==0){ $count--; }elseif(strcasecmp($socket,"FAD20000")==0){ return true; break; }else{ $is = call_user_func($failCall, "0", "错误"); if($is === false) return false; } } $is = call_user_func($failCall, "01", "重发次数超出"); if($is === false) return false; } return false; } // 长度补充 function replenStr($str, $len, $swap = 0, $replenField = "0") { $str = str_pad($str, $len, $replenField, STR_PAD_LEFT); if ($swap == 1) { // 交换高低位 $lhbyte = swapHilo($str); $str = $lhbyte["lbyte"] . $lhbyte["hbyte"]; } return $str; } // 交换高低位 function swapHilo($num) { // 先转换为10进制数 $num = hexdec($num); $hbyte = dechex(floor($num / 256)); $lbyte = dechex($num % 256); if (strlen($hbyte) <= 1) $hbyte = "0" . $hbyte; if (strlen($lbyte) <= 1) $lbyte = "0" . $lbyte; return ["hbyte" => $hbyte, "lbyte" => $lbyte]; } function jsonCmdStr($cmd = "", $data = []) { return json_encode(["cmd" => $cmd, "data" => $data]); } function getSerial() { global $hexSerial; $lowerLimit = 0x6FFFFF; $upperLimit = 0xAFFFFF; $hexSerial++; // 检查是否超出上限,如果超出则重新从下限开始 if ($hexSerial > $upperLimit) { $hexSerial = $lowerLimit; } // 将整数转换为 24 位无符号整数的二进制表示 $binaryData = pack('N', $hexSerial); // 取后 3 个字节(24 位)的数据 $binaryData = substr($binaryData, 1); // 将二进制数据反转(高低位交换) $reversedData = strrev($binaryData); // 将反转后的二进制数据转换为十六进制字符串 $hexSerialNumber = bin2hex($reversedData); return str_split($hexSerialNumber, 2); } function writeLog($msg){ $dir = __DIR__ . "/../logs/patch/"; // 日志目录不存在 if(!file_exists($dir)) mkdir($dir, 0777, true); $filename = $dir ."rewriteTheSchedule.log"; // 日志文件不存在 if(!file_exists($filename)){ file_put_contents($filename, ""); chmod($filename, 0777); } // 写入日志 file_put_contents($filename, $msg . "\n", FILE_APPEND); }