RL4RSSI_INDOOR_MQTT.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. <?php
  2. require('../vendor/autoload.php');
  3. use \PhpMqtt\Client\MqttClient;
  4. use \PhpMqtt\Client\ConnectionSettings;
  5. use think\facade\Cache;
  6. date_default_timezone_set("PRC");
  7. define('HOST', '127.0.0.1');
  8. define('PORT', '6379');
  9. define('PASSWORD', 'R!478gH*%23nPn');
  10. // define('PASSWORD', '123456');
  11. define('DATABASE', 2);
  12. function app_redis()
  13. {
  14. static $redis = null;
  15. static $conn = false;
  16. if (!$conn) {
  17. connect: //定义标签
  18. $redis = new Redis();
  19. try {
  20. //建立的Redis短连接,在请求结束后不会自动关闭,相当于持久连接.
  21. $conn = $redis->connect(HOST, PORT);
  22. $conn = $redis->auth(PASSWORD);
  23. $conn = $redis->select(DATABASE);
  24. // 连接成功,返回$redis对象,连接失败,返回false.
  25. return ($conn === true) ? $redis : false;
  26. } catch (Exception $e) {
  27. return false;
  28. }
  29. } else {
  30. // 这里假设PHP-FPM在处理一个请求的时间内,Redis连接都是可用的.
  31. // 所以只在PHP-CLI下检查Redis连接的状态,进行断线重连.
  32. if (php_sapi_name() === 'cli') {
  33. try {
  34. // ping用于检查当前连接的状态,成功时返回+PONG,失败时抛出一个RedisException对象.
  35. // ping失败时警告:
  36. // Warning: Redis::ping(): connect() failed: Connection refused
  37. // var_dump('AAAAAAAAA', $redis);
  38. echo 'Redis 连接状态' . $redis->ping() . PHP_EOL;
  39. @$redis->ping();
  40. if (!$redis->ping()) {
  41. goto connect; //跳转到标签出继续执行连接操作
  42. }
  43. } catch (Exception $e) {
  44. // 信息如 Connection lost 或 Redis server went away
  45. echo $e->getMessage();
  46. echo 'Redis 连接失败 重新连接:' . PHP_EOL;
  47. // 断线重连
  48. goto connect;
  49. }
  50. }
  51. return $redis;
  52. }
  53. }
  54. function rlog(...$args)
  55. {
  56. if (empty($args[0])) {
  57. return;
  58. }
  59. static $LOG_CONSOLE = false; //是否输出到控制台
  60. static $LOG_NAME = "rl4rssi_indoor_mqtt.log"; //值为空时 不写入文件
  61. static $LOG_SIZE = 64 * 1024 * 1024; //文件最大尺寸
  62. static $LOG_CACHE = false; //是否缓存日志内容 用于批量写入文件
  63. static $CACHE_DURATION = 10; //缓存最大时间 秒
  64. static $CACHE_SIZE = 1024; //缓存大小
  65. static $cacheStartTime = 0;
  66. static $cacheBuf = '';
  67. static $LOG_TIMES = 10; //调用这个函数最大次数 超过次数后判断下文件大小
  68. static $logCount = 0;
  69. $buf = '';
  70. if (count($args) == 1 && $args[0] == "\n") { //只有换行时 不写入时间戳了
  71. $buf = "\n";
  72. } else {
  73. $pid = ''; //进程id
  74. if (function_exists('posix_getpid')) {
  75. $pid = ' ' . posix_getpid() . ' ';
  76. }
  77. $fileLine = ''; //文件名:行号
  78. {
  79. $debug = debug_backtrace();
  80. $fileLine = ($pid == '' ? ' ' : '') . basename($debug[0]['file']) . ':' . $debug[0]['line'] . ' ';
  81. }
  82. $buf = date("y-m-d H:i:s") . "{$pid}{$fileLine}" . implode(' ', $args) . "\n";
  83. }
  84. $logCount++;
  85. if (!empty($LOG_NAME)) {
  86. if ($LOG_CACHE) {
  87. $cacheBuf .= $buf;
  88. //超过缓存尺寸 或者 超过缓存时长 写缓存到文件
  89. if (strlen($cacheBuf) > $CACHE_SIZE || time() - $cacheStartTime > $CACHE_DURATION) {
  90. $cacheStartTime = time();
  91. goto write;
  92. } else {
  93. goto skipWrite;
  94. }
  95. } else {
  96. $cacheBuf = $buf;
  97. }
  98. write: {
  99. //超过尺寸后 删除旧文件 把新文件重命名为旧文件 多进程同时操作 不加锁问题不大
  100. if ($logCount > $LOG_TIMES && filesize($LOG_NAME) > $LOG_SIZE) {
  101. $oldLogName = $LOG_NAME . '.old';
  102. if (file_exists($oldLogName)) {
  103. if (!unlink($oldLogName)) {
  104. echo "unlink err\n";
  105. }
  106. }
  107. if (!rename($LOG_NAME, $oldLogName)) {
  108. echo "rename err\n";
  109. }
  110. $logCount = 0;
  111. }
  112. if (!file_put_contents($LOG_NAME, $cacheBuf, FILE_APPEND)) {
  113. echo "file_put_contents err\n";
  114. }
  115. $cacheBuf = '';
  116. }
  117. skipWrite: {
  118. }
  119. }
  120. if ($LOG_CONSOLE) {
  121. echo $buf;
  122. }
  123. }
  124. function http($url, $params, $header = [], $method = 'GET', $timeout = 10)
  125. {
  126. // POST $params 字符串形式query=abcd&abc=12345
  127. //GET $params 数组['query' => 'abcd', 'abc' => 12345]
  128. // $header[] = "Content-Type: application/x-www-form-urlencoded";
  129. // $header[] = "Content-Type: application/soap+xml; charset=utf-8";
  130. // $header[] = "Content-Type: application/json; charset=utf-8";
  131. // $header[] = "Expect: ";
  132. rlog("[HTTP] url:$url,method:$method" . ",header:" . json_encode($header));
  133. if (strtoupper($method) == 'POST') {
  134. rlog("[POST] send params " . (!is_array($params) ? $params : json_encode($params, JSON_UNESCAPED_UNICODE)));
  135. } else {
  136. rlog("[GET] send " . json_encode($params));
  137. }
  138. $header[] = "Expect: ";
  139. $opts = array(
  140. CURLOPT_TIMEOUT => $timeout,
  141. CURLOPT_RETURNTRANSFER => 1,
  142. CURLOPT_SSL_VERIFYPEER => false,
  143. CURLOPT_SSL_VERIFYHOST => false,
  144. CURLOPT_HTTPHEADER => $header
  145. );
  146. /* 根据请求类型设置特定参数 */
  147. switch (strtoupper($method)) {
  148. case 'GET':
  149. $opts[CURLOPT_URL] = $url . (empty($params) ? '' : ('?' . http_build_query($params)));
  150. break;
  151. case 'POST':
  152. //$params = http_build_query($params);
  153. $opts[CURLOPT_URL] = $url;
  154. $opts[CURLOPT_POST] = 1;
  155. $opts[CURLOPT_POSTFIELDS] = json_encode($params);
  156. break;
  157. default:
  158. rlog("[ERR] method " . $method);
  159. return false;
  160. }
  161. global $ch; //curl长连接
  162. if (empty($ch)) {
  163. $ch = curl_init();
  164. }
  165. if (empty($ch)) {
  166. rlog("[ERR] curl_init");
  167. return false;
  168. }
  169. $csa = curl_setopt_array($ch, $opts);
  170. if (empty($csa)) {
  171. rlog("[ERR] curl_setopt_array");
  172. return false;
  173. }
  174. $data = curl_exec($ch);
  175. if ($data === false) {
  176. rlog("[ERR] curl_exec errno:" . curl_errno($ch) . " " . curl_error($ch));
  177. return false;
  178. }
  179. //unicode转中文
  180. $data = decodeUnicode($data);
  181. rlog("[HTTP] recv " . $data);
  182. //curl_close($ch);
  183. return $data;
  184. }
  185. function decodeUnicode($str)
  186. {
  187. return preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function ($matches) {
  188. return iconv("UCS-2BE", "UTF-8", pack("H*", $matches[1]));
  189. }, $str);
  190. }
  191. function devRegularInfo($topic, $msg)
  192. {
  193. // {"CSQ":26,"REP_INT":60,"GPS":"112.14060,32.06532","IMEI":"867160049332715","IMSI":"460041872816952","CCID":"898607B8101980060659","SYS_VER":"RLSC_V0.1","Time":1676257143,"Status":0,"StatusMsg":"设备正常","Initiative":1}
  194. $data = json_decode($msg, true);
  195. if (empty($data)) {
  196. rlog("ERR", "json_decode");
  197. return;
  198. }
  199. rlog("[I]", $msg);
  200. $url = 'http://47.114.185.186:8115/api/trackReport';
  201. // $url .= http_build_query($column);
  202. http($url, $data, [], 'POST');
  203. $loc = explode(',', $data['GPS']);
  204. $column = [
  205. 'csq' => $data['CSQ'] ?: '',
  206. 'rep_int' => $data['REP_INT'] ?: '',
  207. 'latitude' => isset($loc[0]) ? $loc[0] : '',
  208. 'longitude' => isset($loc[1]) ? $loc[1] : '',
  209. 'imei' => $data['IMEI'] ?: '',
  210. 'imsi' => $data['IMSI'] ?: '',
  211. 'iccid' => $data['ICCID'] ?: '',
  212. 'version' => $data['SYS_VER'] ?: '',
  213. 'time' => $data['Time'] ?: '',
  214. 'status' => $data['Status'] ?: '',
  215. 'status_msg' => $data['StatusMsg'] ?: '',
  216. 'initiative' => $data['Initiative'] ?: ''
  217. ];
  218. $url = 'http://47.114.185.186:8115/rlapi/busHeartbeatData';
  219. // $url .= http_build_query($column);
  220. http($url, $column, [], 'POST');
  221. }
  222. function getUpDevSysMsg($topic, $msg)
  223. {
  224. // {
  225. // "IMEI": "867160049332715",
  226. // "Mqtt_Host": "develop.rltest.cn",
  227. // "Mqtt_Port": 1883,
  228. // "Mqtt_User": " rl517",
  229. // "Mqtt_Password": "rlian2022",
  230. // "TTS_TEXT": "某某科技欢迎您",
  231. // "GPS_EN": "0",
  232. // "Time": 1676257143
  233. // }
  234. $arr = json_decode($msg, true);
  235. if (empty($arr)) {
  236. rlog("ERR", "json_decode");
  237. return;
  238. }
  239. $column = [
  240. 'imei' => $arr['IMEI'],
  241. 'mqtt_host' => $arr['Mqtt_Host'],
  242. 'mqtt_port' => $arr['Mqtt_Port'],
  243. 'mqtt_user' => $arr['Mqtt_User'],
  244. 'mqtt_password' => $arr['Mqtt_Password'],
  245. 'tts_text' => $arr['TTS_TEXT'],
  246. 'gps_en' => $arr['GPS_EN'],
  247. 'time' => $arr['Time']
  248. ];
  249. $url = 'http://47.114.185.186:8115/rlapi/busSysMsgData';
  250. // $url .= http_build_query($data);
  251. http($url, $column, [], 'POST');
  252. }
  253. function rcInfoMsg($topic, $msg)
  254. {
  255. // {
  256. // "IMEI": "867160049332715",
  257. // "RC_Number": "867160049332715",
  258. // "RC_Type": 1,
  259. // "RC_Pres": 1,
  260. // "RC_Total": 25,
  261. // "GPS_X": "116.25"
  262. // "GPS_Y": "29.36",
  263. // "Msgid": "dkx12-15dss-ad567-1a2ss",
  264. // "Time": 1676257143
  265. // }
  266. $arr = json_decode($msg, true);
  267. if (empty($arr)) {
  268. rlog("ERR", "json_decode");
  269. return;
  270. }
  271. $column = [
  272. 'imei' => $arr['IMEI'],
  273. 'rc_number' => $arr['RC_Number'],
  274. 'rc_type' => $arr['RC_Type'],
  275. 'rc_pres' => $arr['RC_Pres'],
  276. 'rc_total' => $arr['RC_Total'],
  277. 'gps_x' => $arr['GPS_X'],
  278. 'gps_y' => $arr['GPS_Y'],
  279. 'msgid' => $arr['Msgid'],
  280. 'time' => $arr['Time']
  281. ];
  282. $url = 'http://47.114.185.186:8115/rlapi/busRcInfoData';
  283. // $url .= http_build_query($data);
  284. http($url, $column, [], 'POST');
  285. }
  286. function loop()
  287. {
  288. $server = '127.0.0.1';
  289. $port = 1883;
  290. $clientId = 'mqttx_testindoor'.rand(1234, 99999);
  291. $username = 'rl0606';
  292. $password = "rlian2023";
  293. $clean_session = true;
  294. $connectionSettings = new ConnectionSettings();
  295. $connectionSettings = $connectionSettings
  296. ->setUsername($username)
  297. ->setPassword($password)
  298. ->setKeepAliveInterval(60)
  299. // Last Will 设置
  300. // ->setLastWillTopic('emqx/test/last-will')
  301. // ->setLastWillMessage('client disconnect')
  302. // ->setLastWillQualityOfService(1)
  303. ;
  304. //include "RLog.php";
  305. // $mqtt = new MqttClient($server, $port, $clientId, MqttClient::MQTT_3_1, null, new RLog());
  306. $mqtt = new MqttClient($server, $port, $clientId);
  307. $mqtt->connect($connectionSettings, $clean_session);
  308. rlog('INFO', "connect OK");
  309. /*
  310. 消息方向 设备->服务器
  311. 设备主动上报当前设备公共信息参数:ScBusTem/DevRegularInfo
  312. 服务器获取设备系统信息后设备上传信息,即GetDevSysMsg的回应 ScBusTem/GetUpDevSysMsg
  313. 服务器设置设备重量信息信息 ScBusTem/RCInfoMsg
  314. */
  315. //订阅心跳数据
  316. $mqtt->subscribe('PArea4RSSI/devOntime', function ($topic, $message) {
  317. rlog("INFO", 'recv', $topic, $message);
  318. var_dump($message);
  319. }, 0);
  320. // $mqtt->subscribe('ScBusTem/GetDevSysMsg/*', function ($topic, $message) {
  321. // rlog("INFO", 'recv', $topic, $message);
  322. // getDevSysMsg($topic, $message);
  323. // }, 0);
  324. //终端上报系统信息数据
  325. $mqtt->subscribe('RL4RSSI/IndoorRfids', function ($topic, $message) {
  326. rlog("INFO", 'recv', $topic, $message);
  327. if(!empty($message)){
  328. mqttToRedis($message);
  329. }
  330. }, 0);
  331. $mqtt->loop(true);
  332. }
  333. // FFFFFFFFFF000014FF000002200000E2B15AD501FFFFFFFF49FFFF46
  334. // 5bc6f8a110FFFFFFFF474d4a49
  335. function mqttToRedis($text){
  336. try{
  337. app_redis()->lpush("mqtt_data_indoor4rssi",$text);
  338. }catch(\Exception $e){
  339. rlog("INFO", 'recv',"redis 异常".$e->getMessage());
  340. }
  341. }
  342. while (1) {
  343. try {
  344. rlog('INFO', 'connect start');
  345. loop();
  346. } catch (\Exception $ex) {
  347. rlog("ERR", $ex->getTraceAsString());
  348. rlog("ERR", $ex->getMessage());
  349. }
  350. sleep(3);
  351. }