From e491cdb48129752324c4e3764f99bd9203c56dec Mon Sep 17 00:00:00 2001
From: lgq <1015864684@qq.com>
Date: 星期二, 31 三月 2026 09:48:44 +0800
Subject: [PATCH] 1.新增VF205门禁机代码

---
 vf205_access/src/service/grainService.js |  676 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 676 insertions(+), 0 deletions(-)

diff --git a/vf205_access/src/service/grainService.js b/vf205_access/src/service/grainService.js
new file mode 100644
index 0000000..4c5721c
--- /dev/null
+++ b/vf205_access/src/service/grainService.js
@@ -0,0 +1,676 @@
+/**
+ * 绮儏鏈嶅姟妯″潡
+ * 璐熻矗姘斾綋娴撳害鏁版嵁鑾峰彇鍜岀姸鎬佷俊鎭暟鎹幏鍙�
+ */
+import logger from "../../dxmodules/dxLogger.js"
+import config from "../../dxmodules/dxConfig.js"
+import http from "../../dxmodules/dxHttp.js"
+import bus from '../../dxmodules/dxEventBus.js'
+import std from "../../dxmodules/dxStd.js"
+import driver from "../driver.js"
+const grainService = {}
+
+// 浠庨厤缃腑鑾峰彇涓氬姟缂栫爜瀹氫箟
+const functionId = {
+    gasDetection: config.get('functionId.gasDetection') || "1000",
+    safeInputControl: config.get('functionId.safeInputControl') || "2000",
+    lightControl: config.get('functionId.lightControl') || "3000",
+    doorStatus: config.get('functionId.doorStatus') || "4000"
+}
+
+// 浠庨厤缃腑鑾峰彇鎺ュ彛杩斿洖缂栫爜
+const respCode = {
+    success: config.get('respCode.success') || "200",
+    badRequest: config.get('respCode.badRequest') || "400",
+    unauthorized: config.get('respCode.unauthorized') || "401",
+    forbidden: config.get('respCode.forbidden') || "403",
+    notFound: config.get('respCode.notFound') || "404",
+    serverError: config.get('respCode.serverError') || "500"
+}
+
+// 閿欒鐮佸搴旂殑閿欒淇℃伅
+const errorMessages = {
+    "400": "璇锋眰鍙傛暟鏈夎",
+    "401": "鏈櫥褰曪紝鐢ㄦ埛涓嶅瓨鍦�",
+    "403": "鐢ㄦ埛鏃犳潈闄�",
+    "404": "璇锋眰鍔熻兘涓嶅瓨鍦�",
+    "500": "璇锋眰鎵ц寮傚父锛岃鑱旂郴绠$悊鍛�"
+}
+
+// 鎿嶄綔鎸夐挳瀵瑰簲鐨勮闊虫枃浠�
+const voiceFiles = {
+    // 鍏佽杩涗粨妯″紡
+    "11": "btn11.wav", // 鍏佽杩涗粨妯″紡
+    "12": "btn12.wav", // 鍏ヤ粨
+    "13": "btn13.wav", // 鍑轰粨
+    // 鍐閫氶妯″紡
+    "21": "btn21.wav", // 鍐閫氶妯″紡
+    "22": "btn22.wav", // 鍚姩
+    "23": "btn23.wav", // 鍏抽棴
+    // 绂佹杩涗粨妯″紡
+    "31": "btn31.wav", // 绂佹杩涗粨妯″紡
+    "32": "btn32.wav", // 绱ф�ュ叆浠�
+    "33": "btn33.wav", // 鍑轰粨
+    // 鐓ф槑鎺у埗
+    "light_open": "light_open.wav", // 寮�鐏�
+    "light_close": "light_close.wav" // 鍏崇伅
+}
+
+/**
+ * 鏍规嵁閿欒鐮佽幏鍙栭敊璇俊鎭�
+ * @param {string} code - 閿欒鐮�
+ * @returns {string} 閿欒淇℃伅
+ */
+function getErrorMessage(code) {
+    return errorMessages[code] || "鎿嶄綔澶辫触"
+}
+
+/**
+ * 鏍规嵁鎿嶄綔鎸夐挳鍜屽姛鑳界爜鑾峰彇璇煶鏂囦欢
+ * @param {string} functionId - 鍔熻兘鐮�
+ * @param {object} params - 璇锋眰鍙傛暟锛屽寘鍚玬ode鍜宐tn
+ * @returns {string} 璇煶鏂囦欢璺緞
+ */
+function getVoiceFile(functionId, params) {
+    // 鐓ф槑鎺у埗鍔熻兘
+    if (functionId === "3000") {
+        // 寮�鐏�
+        if (String(params.btn) === "1") return voiceFiles["light_open"]
+        // 鍏崇伅
+        if (String(params.btn) === "2") return voiceFiles["light_close"]
+    }
+    // 瀹夊叏鍏ヤ粨鎺у埗鍔熻兘
+    if (functionId === "2000" && params) {
+        const { mode, btn } = params
+        // 妯″紡1: 鍏佽杩涗粨妯″紡
+        if (mode === 1) {
+            if (!btn) return voiceFiles["11"] // 鍏佽杩涗粨妯″紡鎸夐挳
+            if (String(btn) === "1") return voiceFiles["12"] // 鍏ヤ粨鎸夐挳
+            if (String(btn) === "2") return voiceFiles["13"] // 鍑轰粨鎸夐挳
+        }
+        // 妯″紡2: 鍐閫氶妯″紡
+        if (mode === 2) {
+            if (!btn) return voiceFiles["21"] // 鍐閫氶妯″紡鎸夐挳
+            if (String(btn) === "1") return voiceFiles["22"] // 鍚姩鎸夐挳
+            if (String(btn) === "2") return voiceFiles["23"] // 鍏抽棴鎸夐挳
+        }
+        // 妯″紡3: 绂佹杩涗粨妯″紡
+        if (mode === 3) {
+            if (!btn) return voiceFiles["31"] // 绂佹杩涗粨妯″紡鎸夐挳
+            if (String(btn) === "1") return voiceFiles["32"] // 绱ф�ュ叆浠撴寜閽�
+            if (String(btn) === "2") return voiceFiles["33"] // 鍑轰粨鎸夐挳
+        }
+    }
+    return null
+}
+
+// 浠庨厤缃腑鑾峰彇HTTP鎺ュ彛璺緞
+function getHttpUrl() {
+    return config.get('http.safeInputAccess') || "http://192.168.1.199:80/cgi-bin/safeInputAccess"
+}
+
+// 瀛樺偍姘斾綋娴撳害鏁版嵁
+let gasDataStorage = null
+
+/**
+ * 妫�鏌ユ皵浣撴祿搴�
+ * @param {function} callback - 鍥炶皟鍑芥暟锛屽湪姘斾綋娴撳害妫�娴嬪畬鎴愬悗璋冪敤
+ * @returns {boolean} true琛ㄧず姘斾綋娴撳害鍚堟牸锛宖alse琛ㄧず姘斾綋娴撳害涓嶅悎鏍�
+ */
+grainService.checkGasConcentration = function(callback) {
+    // 浣跨敤setTimeout灏咹TTP璇锋眰鏀惧叆鍚庡彴鎵ц锛岄伩鍏嶉樆濉炰富绾跨▼
+    std.setTimeout(() => {
+        try {
+            // 纭繚URL鏍煎紡姝g‘锛屾坊鍔爃ttp://鍓嶇紑
+            let url = getHttpUrl()
+            if (!url.startsWith('http://') && !url.startsWith('https://')) {
+                url = 'http://' + url
+            }
+            
+            const timeout = 3000 // 3绉掕秴鏃�
+            
+            logger.info(`[grain]: 姝e湪鑾峰彇姘斾綋娴撳害鏁版嵁: ${url}`)
+            
+            // 鏋勫缓POST璇锋眰鏁版嵁
+            const postData = {
+                sn: config.get("sys.sn") || " ", // 璁惧搴忓垪鍙凤紝浠庨厤缃腑鑾峰彇
+                houseId: "0000", // 浠撳粧缂栫爜锛岄粯璁ゅ~鍏�"0000"
+                outId: "0000", // 鑷畾涔夌紪鐮侊紝榛樿濉厖"0000"
+                functionId: functionId.gasDetection, // 姘斾綋娴撳害妫�娴嬪姛鑳界爜
+                timestamp: Date.now().toString() // 鏃堕棿鎴�
+            }
+            
+            logger.info(`[grain]: 鍙戦�丳OST璇锋眰鏁版嵁: ${JSON.stringify(postData)}`)
+            
+            // 鍙戦�丠TTP POST璇锋眰
+            let response = http.post(url, postData, timeout)
+            
+            // logger.info(`[grain]: 姘斾綋娴撳害鏁版嵁鍝嶅簲: ${JSON.stringify(response)}`)
+            
+            // 瑙f瀽鍝嶅簲鏁版嵁
+            // 妫�鏌esponse鏄惁涓哄瓧绗︿覆锛屽鏋滄槸鍒欒В鏋愪负瀵硅薄
+            if (typeof response === 'string') {
+                response = JSON.parse(response)
+            }
+            
+            if (response && response.body) {
+                // 瑙f瀽鍝嶅簲浣�
+                let gasData
+                try {
+                    gasData = JSON.parse(response.body)
+                    logger.info(`[grain]: 瑙f瀽鍚庣殑姘斾綋娴撳害鏁版嵁: ${JSON.stringify(gasData)}`)
+                    
+                    // 鏍规嵁鎺ュ彛杩斿洖缂栫爜杩涜鏃ュ織杈撳嚭
+                    if (gasData.respCode === respCode.success) {
+                        logger.info(`[grain]: 姘斾綋娴撳害妫�娴嬫帴鍙h皟鐢ㄦ垚鍔焋)
+                    } else {
+                        logger.error(`[grain]: 姘斾綋娴撳害妫�娴嬫帴鍙h皟鐢ㄥけ璐ワ紝杩斿洖缂栫爜: ${gasData.respCode}, 杩斿洖淇℃伅: ${gasData.respMsg}`)
+                    }
+                } catch (parseError) {
+                    logger.error(`[grain]: 瑙f瀽姘斾綋娴撳害鏁版嵁澶辫触: ${parseError.message}`)
+                    // 灏濊瘯娓呯悊鍝嶅簲浣撲腑鐨勮浆涔夊瓧绗�
+                    try {
+                        // 绉婚櫎澶氫綑鐨勮浆涔夊瓧绗�
+                        const cleanedBody = response.body.replace(/\\r\\n/g, '').replace(/\\t/g, '').replace(/\"/g, '"')
+                        gasData = JSON.parse(cleanedBody)
+                        logger.info(`[grain]: 娓呯悊鍚庤В鏋愮殑姘斾綋娴撳害鏁版嵁: ${JSON.stringify(gasData)}`)
+                        
+                        // 鏍规嵁鎺ュ彛杩斿洖缂栫爜杩涜鏃ュ織杈撳嚭
+                        if (gasData.respCode === respCode.success) {
+                            logger.info(`[grain]: 姘斾綋娴撳害妫�娴嬫帴鍙h皟鐢ㄦ垚鍔焋)
+                        } else {
+                            logger.error(`[grain]: 姘斾綋娴撳害妫�娴嬫帴鍙h皟鐢ㄥけ璐ワ紝杩斿洖缂栫爜: ${gasData.respCode}, 杩斿洖淇℃伅: ${gasData.respMsg}`)
+                        }
+                    } catch (cleanError) {
+                        logger.error(`[grain]: 娓呯悊鍚庤В鏋愭皵浣撴祿搴︽暟鎹粛澶辫触: ${cleanError.message}`)
+                        // 璋冪敤鍥炶皟鍑芥暟
+                        if (callback) {
+                            callback()
+                        }
+                        return
+                    }
+                }
+                
+                // 瀛樺偍姘斾綋鏁版嵁
+                gasDataStorage = gasData
+                
+                // 妫�鏌ユ皵浣撴祿搴︽槸鍚﹀悎鏍�
+                // 鏂版牸寮�: {"value":[{"o2":"20.5","statusO2":"0","co2":"401","statusCo2":"0","ph3":"0","statusPh3":"0"}],"status":"1"}
+                // statusO2/statusCo2/statusPh3: "0"琛ㄧず鍚堟牸锛�"1"琛ㄧず涓嶅悎鏍硷紙浠呯敤浜嶶I鏄剧ず锛�
+                // data.status: "0"琛ㄧず鏈�缁堝悎鏍硷紝"1"琛ㄧず鏈�缁堜笉鍚堟牸
+                const gasValue = gasData.data && gasData.data.value ? gasData.data.value[0] : null
+                const isO2Qualified = gasValue && gasValue.statusO2 === "0"
+                const isCo2Qualified = gasValue && gasValue.statusCo2 === "0"
+                const isPh3Qualified = gasValue && gasValue.statusPh3 === "0"
+                
+                // 瑙﹀彂浜嬩欢鏇存柊UI
+                bus.fire('gasConcentrationUpdated', gasData)
+                
+                // 鏈�缁堝悎鏍煎垽鏂彧渚濊禆status瀛楁鍊�
+                const isAllQualified = gasData.data && gasData.data.status === "0"
+                
+                if (isAllQualified) {
+                    logger.info("[grain]: 姘斾綋娴撳害妫�娴嬪悎鏍�")
+                } else {
+                    logger.info("[grain]: 姘斾綋娴撳害妫�娴嬩笉鍚堟牸")
+                }
+                
+                // 璋冪敤鍥炶皟鍑芥暟
+                if (callback) {
+                    callback()
+                }
+            } else {
+                logger.error(`[grain]: 姘斾綋娴撳害鏁版嵁鑾峰彇澶辫触: ${response ? "鏃犲搷搴斾綋" : "鏃犲搷搴�"}`)
+                // 璋冪敤鍥炶皟鍑芥暟
+                if (callback) {
+                    callback()
+                }
+            }
+        } catch (error) {
+            logger.error(`[grain]: 姘斾綋娴撳害妫�娴嬮敊璇�: ${error.message}`)
+            // 璋冪敤鍥炶皟鍑芥暟
+            if (callback) {
+                callback()
+            }
+        }
+    }, 0)
+    
+    // 绔嬪嵆杩斿洖锛岄伩鍏嶉樆濉炰富绾跨▼
+    return true
+}
+
+/**
+ * 鑾峰彇瀛樺偍鐨勬皵浣撴祿搴︽暟鎹�
+ * @returns {object|null} 瀛樺偍鐨勬皵浣撴祿搴︽暟鎹紝濡傛灉娌℃湁鍒欒繑鍥瀗ull
+ */
+grainService.getGasData = function() {
+    return gasDataStorage
+}
+
+/**
+ * 妫�鏌ヨ澶囩姸鎬佷俊鎭�
+ * @param {object} params - 璇锋眰鍙傛暟
+ * @param {string} params.user1 - 浜鸿劯璇嗗埆鐢ㄦ埛1
+ * @param {string} params.user2 - 浜鸿劯璇嗗埆鐢ㄦ埛2
+ * @param {string} params.mode - 閫夋嫨妯″紡锛�1-鍏佽鍏ヤ粨锛�2-鍐閫氶锛�3-绂佹鍏ヤ粨锛�
+ * @param {string} params.btn - 鎿嶄綔鎸夐挳锛�1-鍏ヤ粨/寮�鍚紱2-鍑轰粨/鍏抽棴锛�
+ * @returns {boolean} true琛ㄧず鐘舵�佷俊鎭幏鍙栨垚鍔燂紝false琛ㄧず澶辫触
+ */
+grainService.checkDevConcentration = function(params) {
+    // 浣跨敤setTimeout灏咹TTP璇锋眰鏀惧叆鍚庡彴鎵ц锛岄伩鍏嶉樆濉炰富绾跨▼
+    std.setTimeout(() => {
+        try {
+            // 纭繚URL鏍煎紡姝g‘锛屾坊鍔爃ttp://鍓嶇紑
+            let url = getHttpUrl()
+            if (!url.startsWith('http://') && !url.startsWith('https://')) {
+                url = 'http://' + url
+            }
+            
+            const timeout = 3000 // 3绉掕秴鏃�
+            
+            // logger.info(`[grain]: 姝e湪鑾峰彇鐘舵�佷俊鎭暟鎹�: ${url}`)
+            
+            // 鏋勫缓POST璇锋眰鏁版嵁
+            const postData = {
+                sn: config.get("sys.sn") || " ", // 璁惧搴忓垪鍙凤紝浠庨厤缃腑鑾峰彇
+                houseId: "0000", // 浠撳粧缂栫爜锛岄粯璁ゅ~鍏�"0000"
+                outId: "0000", // 鑷畾涔夌紪鐮侊紝榛樿濉厖"0000"
+                functionId: params && params.functionId ? params.functionId : functionId.safeInputControl, // 鍔熻兘鐮侊紝榛樿涓哄畨鍏ㄥ叆浠撹仈鍔ㄦ帶鍒�
+                timestamp: Date.now().toString(), // 鏃堕棿鎴�
+                data: {}
+            }
+            
+            // 娣诲姞鍙�夊弬鏁�
+            if (params) {
+                if (params.user1) postData.data.user1 = params.user1
+                if (params.user2) postData.data.user2 = params.user2
+                if (params.mode) postData.data.mode = params.mode
+                if (params.btn) postData.data.btn = params.btn
+            }
+            
+            logger.info(`[grain]: 鍙戦�丳OST璇锋眰鏁版嵁: ${JSON.stringify(postData)}`)
+            
+            // 鍙戦�丠TTP POST璇锋眰
+            let response = http.post(url, postData, timeout)
+            
+            // logger.info(`[grain]: 鐘舵�佷俊鎭暟鎹搷搴�: ${JSON.stringify(response)}`)
+            
+            // 瑙f瀽鍝嶅簲鏁版嵁
+            // 妫�鏌esponse鏄惁涓哄瓧绗︿覆锛屽鏋滄槸鍒欒В鏋愪负瀵硅薄
+            if (typeof response === 'string') {
+                response = JSON.parse(response)
+            }
+            
+            if (response && response.body) {
+                // 瑙f瀽鍝嶅簲浣�
+                let statusData
+                try {
+                    statusData = JSON.parse(response.body)
+                    logger.info(`[grain]: 瑙f瀽鍚庣殑鐘舵�佷俊鎭暟鎹�: ${JSON.stringify(statusData)}`)
+                    
+                    // 鏍规嵁鎺ュ彛杩斿洖缂栫爜杩涜鏃ュ織杈撳嚭
+                    if (statusData.respCode === respCode.success) {
+                        logger.info(`[grain]: 鐘舵�佷俊鎭帴鍙h皟鐢ㄦ垚鍔焋)
+                        // 妫�鏌ata鏄惁涓虹┖锛屼笉涓虹┖鎵嶈Е鍙戦�氱煡
+                        if (Object.keys(postData.data).length > 0) {
+                            // 瑙﹀彂鎴愬姛寮圭獥
+                            bus.fire('showAccessResult', {
+                                faceAuth: true,
+                                gasConcentration: true,
+                                accessAllowed: true,
+                                message: '*鎵ц鎴愬姛*'
+                            })
+                            
+                            // 鎾斁鎴愬姛璇煶鎻愮ず
+                            try {
+                                const voiceFile = getVoiceFile(postData.functionId, postData.data)
+                                if (voiceFile) {
+                                    driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/${voiceFile}`)
+                                    logger.info(`[grain]: 鎾斁鎴愬姛璇煶鎻愮ず: ${voiceFile}`)
+                                }
+                            } catch (error) {
+                                logger.error(`[grain]: 鎾斁璇煶鎻愮ず澶辫触: ${error.message}`)
+                            }
+                        }
+                    } else {
+                        logger.error(`[grain]: 鐘舵�佷俊鎭帴鍙h皟鐢ㄥけ璐ワ紝杩斿洖缂栫爜: ${statusData.respCode}, 杩斿洖淇℃伅: ${statusData.respMsg}`)
+                        // 妫�鏌ata鏄惁涓虹┖锛屼笉涓虹┖鎵嶈Е鍙戦�氱煡
+                        if (Object.keys(postData.data).length > 0) {
+                            // 瑙﹀彂澶辫触寮圭獥
+                            bus.fire('showAccessResult', {
+                                faceAuth: true,
+                                gasConcentration: true,
+                                accessAllowed: false,
+                                message: statusData.respMsg || getErrorMessage(statusData.respCode)
+                            })
+                            // 鎾斁澶辫触璇煶鎻愮ず
+                            try {
+                                driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/failed.wav`)
+                                logger.info(`[grain]: 鎾斁澶辫触璇煶鎻愮ず: failed.wav`)
+                            } catch (error) {
+                                logger.error(`[grain]: 鎾斁璇煶鎻愮ず澶辫触: ${error.message}`)
+                            }
+                        }
+                    }
+                } catch (parseError) {
+                    logger.error(`[grain]: 瑙f瀽鐘舵�佷俊鎭暟鎹け璐�: ${parseError.message}`)
+                    // 灏濊瘯娓呯悊鍝嶅簲浣撲腑鐨勮浆涔夊瓧绗�
+                    try {
+                        // 绉婚櫎澶氫綑鐨勮浆涔夊瓧绗�
+                        const cleanedBody = response.body.replace(/\\r\\n/g, '').replace(/\\t/g, '').replace(/\"/g, '"')
+                        statusData = JSON.parse(cleanedBody)
+                        logger.info(`[grain]: 娓呯悊鍚庤В鏋愮殑鐘舵�佷俊鎭暟鎹�: ${JSON.stringify(statusData)}`)
+                        
+                        // 鏍规嵁鎺ュ彛杩斿洖缂栫爜杩涜鏃ュ織杈撳嚭
+                        if (statusData.respCode === respCode.success) {
+                            logger.info(`[grain]: 鐘舵�佷俊鎭帴鍙h皟鐢ㄦ垚鍔焋)
+                            // 妫�鏌ata鏄惁涓虹┖锛屼笉涓虹┖鎵嶈Е鍙戦�氱煡
+                            if (Object.keys(postData.data).length > 0) {
+                                // 瑙﹀彂鎴愬姛寮圭獥
+                                bus.fire('showAccessResult', {
+                                    faceAuth: true,
+                                    gasConcentration: true,
+                                    accessAllowed: true,
+                                    message: '*鎵ц鎴愬姛*'
+                                })
+                                
+                                // 鎾斁鎴愬姛璇煶鎻愮ず
+                                try {
+                                    const voiceFile = getVoiceFile(postData.functionId, postData.data)
+                                    if (voiceFile) {
+                                        driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/${voiceFile}`)
+                                        logger.info(`[grain]: 鎾斁鎴愬姛璇煶鎻愮ず: ${voiceFile}`)
+                                    }
+                                } catch (error) {
+                                    logger.error(`[grain]: 鎾斁璇煶鎻愮ず澶辫触: ${error.message}`)
+                                }
+                            }
+                        } else {
+                            logger.error(`[grain]: 鐘舵�佷俊鎭帴鍙h皟鐢ㄥけ璐ワ紝杩斿洖缂栫爜: ${statusData.respCode}, 杩斿洖淇℃伅: ${statusData.respMsg}`)
+                            // 妫�鏌ata鏄惁涓虹┖锛屼笉涓虹┖鎵嶈Е鍙戦�氱煡
+                            if (Object.keys(postData.data).length > 0) {
+                                // 瑙﹀彂澶辫触寮圭獥
+                                bus.fire('showAccessResult', {
+                                    faceAuth: true,
+                                    gasConcentration: true,
+                                    accessAllowed: false,
+                                    message: statusData.respMsg || getErrorMessage(statusData.respCode)
+                                })
+                                // 鎾斁澶辫触璇煶鎻愮ず
+                                try {
+                                    driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/failed.wav`)
+                                    logger.info(`[grain]: 鎾斁澶辫触璇煶鎻愮ず: failed.wav`)
+                                } catch (error) {
+                                    logger.error(`[grain]: 鎾斁璇煶鎻愮ず澶辫触: ${error.message}`)
+                                }
+                            }
+                        }
+                    } catch (cleanError) {
+                        logger.error(`[grain]: 娓呯悊鍚庤В鏋愮姸鎬佷俊鎭暟鎹粛澶辫触: ${cleanError.message}`)
+                        return false
+                    }
+                }
+                
+                // 瑙﹀彂浜嬩欢鏇存柊UI
+                bus.fire('statusInfoUpdated', statusData)
+                
+                return true
+            } else {
+                logger.error(`[grain]: 鐘舵�佷俊鎭暟鎹幏鍙栧け璐�: ${response ? "鏃犲搷搴斾綋" : "鏃犲搷搴�"}`)
+                // 缃戠粶璇锋眰澶辫触鏃讹紝榛樿杩斿洖false锛堝畨鍏ㄨ捣瑙侊級
+                return false
+            }
+        } catch (error) {
+            logger.error(`[grain]: 鐘舵�佷俊鎭娴嬮敊璇�: ${error.message}`)
+            // 鍙戠敓閿欒鏃讹紝榛樿杩斿洖false锛堝畨鍏ㄨ捣瑙侊級
+            return false
+        }
+    }, 0)
+    
+    // 绔嬪嵆杩斿洖锛岄伩鍏嶉樆濉炰富绾跨▼
+    return true
+}
+
+/**
+ * 浠撳唴鐓ф槑鑱斿姩鎺у埗
+ * @param {object} params - 璇锋眰鍙傛暟
+ * @param {string} params.user1 - 浜鸿劯璇嗗埆鐢ㄦ埛1
+ * @param {string} params.user2 - 浜鸿劯璇嗗埆鐢ㄦ埛2
+ * @param {string} params.btn - 鎿嶄綔鎸夐挳锛�1-寮�鐏紱2-鍏崇伅锛�
+ * @returns {boolean} true琛ㄧず鎺у埗鎴愬姛锛宖alse琛ㄧず鎺у埗澶辫触
+ */
+grainService.controlLight = function(params) {
+    // 浣跨敤setTimeout灏咹TTP璇锋眰鏀惧叆鍚庡彴鎵ц锛岄伩鍏嶉樆濉炰富绾跨▼
+    std.setTimeout(() => {
+        try {
+            // 纭繚URL鏍煎紡姝g‘锛屾坊鍔爃ttp://鍓嶇紑
+            let url = getHttpUrl()
+            if (!url.startsWith('http://') && !url.startsWith('https://')) {
+                url = 'http://' + url
+            }
+            
+            const timeout = 3000 // 3绉掕秴鏃�
+            
+            // 鏋勫缓POST璇锋眰鏁版嵁
+            const postData = {
+                sn: config.get("sys.sn") || " ", // 璁惧搴忓垪鍙凤紝浠庨厤缃腑鑾峰彇
+                houseId: "0000", // 浠撳粧缂栫爜锛岄粯璁ゅ~鍏�"0000"
+                outId: "0000", // 鑷畾涔夌紪鐮侊紝榛樿濉厖"0000"
+                functionId: functionId.lightControl, // 浠撳唴鐓ф槑鑱斿姩鎺у埗鍔熻兘鐮�
+                timestamp: Date.now().toString(), // 鏃堕棿鎴�
+                data: {}
+            }
+            
+            // 娣诲姞鍙�夊弬鏁�
+            if (params) {
+                if (params.user1) postData.data.user1 = params.user1
+                if (params.user2) postData.data.user2 = params.user2
+                if (params.btn) postData.data.btn = params.btn
+            }
+            
+            logger.info(`[grain]: 鍙戦�佷粨鍐呯収鏄庤仈鍔ㄦ帶鍒惰姹傛暟鎹�: ${JSON.stringify(postData)}`)
+            
+            // 鍙戦�丠TTP POST璇锋眰
+            let response = http.post(url, postData, timeout)
+            
+            // 瑙f瀽鍝嶅簲鏁版嵁
+            // 妫�鏌esponse鏄惁涓哄瓧绗︿覆锛屽鏋滄槸鍒欒В鏋愪负瀵硅薄
+            if (typeof response === 'string') {
+                response = JSON.parse(response)
+            }
+            
+            if (response && response.body) {
+                // 瑙f瀽鍝嶅簲浣�
+                let statusData
+                try {
+                    statusData = JSON.parse(response.body)
+                    logger.info(`[grain]: 瑙f瀽鍚庣殑浠撳唴鐓ф槑鑱斿姩鎺у埗鍝嶅簲鏁版嵁: ${JSON.stringify(statusData)}`)
+                    
+                    // 鏍规嵁鎺ュ彛杩斿洖缂栫爜杩涜鏃ュ織杈撳嚭
+                    if (statusData.respCode === respCode.success) {
+                        logger.info(`[grain]: 浠撳唴鐓ф槑鑱斿姩鎺у埗鎺ュ彛璋冪敤鎴愬姛`)
+                        // 瑙﹀彂鎴愬姛寮圭獥
+                        bus.fire('showAccessResult', {
+                            faceAuth: true,
+                            gasConcentration: true,
+                            accessAllowed: true,
+                            message: '*鎵ц鎴愬姛*'
+                        })
+                        
+                        // 鎾斁鎴愬姛璇煶鎻愮ず
+                        try {
+                            const voiceFile = getVoiceFile(postData.functionId, postData.data)
+                            if (voiceFile) {
+                                driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/${voiceFile}`)
+                                logger.info(`[grain]: 鎾斁鎴愬姛璇煶鎻愮ず: ${voiceFile}`)
+                            }
+                        } catch (error) {
+                            logger.error(`[grain]: 鎾斁璇煶鎻愮ず澶辫触: ${error.message}`)
+                        }
+                    } else {
+                        logger.error(`[grain]: 浠撳唴鐓ф槑鑱斿姩鎺у埗鎺ュ彛璋冪敤澶辫触锛岃繑鍥炵紪鐮�: ${statusData.respCode}, 杩斿洖淇℃伅: ${statusData.respMsg}`)
+                        // 瑙﹀彂澶辫触寮圭獥
+                        bus.fire('showAccessResult', {
+                            faceAuth: true,
+                            gasConcentration: true,
+                            accessAllowed: false,
+                            message: statusData.respMsg || getErrorMessage(statusData.respCode)
+                        })
+                        // 鎾斁澶辫触璇煶鎻愮ず
+                        try {
+                            driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/failed.wav`)
+                            logger.info(`[grain]: 鎾斁澶辫触璇煶鎻愮ず: failed.wav`)
+                        } catch (error) {
+                            logger.error(`[grain]: 鎾斁璇煶鎻愮ず澶辫触: ${error.message}`)
+                        }
+                    }
+                } catch (parseError) {
+                    logger.error(`[grain]: 瑙f瀽浠撳唴鐓ф槑鑱斿姩鎺у埗鍝嶅簲鏁版嵁澶辫触: ${parseError.message}`)
+                    // 灏濊瘯娓呯悊鍝嶅簲浣撲腑鐨勮浆涔夊瓧绗�
+                    try {
+                        // 绉婚櫎澶氫綑鐨勮浆涔夊瓧绗�
+                        const cleanedBody = response.body.replace(/\\r\\n/g, '').replace(/\\t/g, '').replace(/\"/g, '"')
+                        statusData = JSON.parse(cleanedBody)
+                        logger.info(`[grain]: 娓呯悊鍚庤В鏋愮殑浠撳唴鐓ф槑鑱斿姩鎺у埗鍝嶅簲鏁版嵁: ${JSON.stringify(statusData)}`)
+                        
+                        // 鏍规嵁鎺ュ彛杩斿洖缂栫爜杩涜鏃ュ織杈撳嚭
+                        if (statusData.respCode === respCode.success) {
+                            logger.info(`[grain]: 浠撳唴鐓ф槑鑱斿姩鎺у埗鎺ュ彛璋冪敤鎴愬姛`)
+                            // 瑙﹀彂鎴愬姛寮圭獥
+                            bus.fire('showAccessResult', {
+                                faceAuth: true,
+                                gasConcentration: true,
+                                accessAllowed: true,
+                                message: '*鎵ц鎴愬姛*'
+                            })
+                            
+                            // 鎾斁鎴愬姛璇煶鎻愮ず
+                            try {
+                                const voiceFile = getVoiceFile(postData.functionId, postData.data)
+                                if (voiceFile) {
+                                    driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/${voiceFile}`)
+                                    logger.info(`[grain]: 鎾斁鎴愬姛璇煶鎻愮ず: ${voiceFile}`)
+                                }
+                            } catch (error) {
+                                logger.error(`[grain]: 鎾斁璇煶鎻愮ず澶辫触: ${error.message}`)
+                            }
+                        } else {
+                            logger.error(`[grain]: 浠撳唴鐓ф槑鑱斿姩鎺у埗鎺ュ彛璋冪敤澶辫触锛岃繑鍥炵紪鐮�: ${statusData.respCode}, 杩斿洖淇℃伅: ${statusData.respMsg}`)
+                            // 瑙﹀彂澶辫触寮圭獥
+                            bus.fire('showAccessResult', {
+                                faceAuth: true,
+                                gasConcentration: true,
+                                accessAllowed: false,
+                                message: statusData.respMsg || getErrorMessage(statusData.respCode)
+                            })
+                            // 鎾斁澶辫触璇煶鎻愮ず
+                            try {
+                                driver.alsa.play(`/app/code/resource/${config.get("base.language") == "CN" ? "CN" : "EN"}/wav/failed.wav`)
+                                logger.info(`[grain]: 鎾斁澶辫触璇煶鎻愮ず: failed.wav`)
+                            } catch (error) {
+                                logger.error(`[grain]: 鎾斁璇煶鎻愮ず澶辫触: ${error.message}`)
+                            }
+                        }
+                    } catch (cleanError) {
+                        logger.error(`[grain]: 娓呯悊鍚庤В鏋愪粨鍐呯収鏄庤仈鍔ㄦ帶鍒跺搷搴旀暟鎹粛澶辫触: ${cleanError.message}`)
+                        return false
+                    }
+                }
+                
+                // 瑙﹀彂浜嬩欢鏇存柊UI
+                bus.fire('statusInfoUpdated', statusData)
+                
+                return true
+            } else {
+                logger.error(`[grain]: 浠撳唴鐓ф槑鑱斿姩鎺у埗璇锋眰澶辫触: ${response ? "鏃犲搷搴斾綋" : "鏃犲搷搴�"}`)
+                // 缃戠粶璇锋眰澶辫触鏃讹紝榛樿杩斿洖false锛堝畨鍏ㄨ捣瑙侊級
+                return false
+            }
+        } catch (error) {
+            logger.error(`[grain]: 浠撳唴鐓ф槑鑱斿姩鎺у埗閿欒: ${error.message}`)
+            // 鍙戠敓閿欒鏃讹紝榛樿杩斿洖false锛堝畨鍏ㄨ捣瑙侊級
+            return false
+        }
+    }, 0)
+    
+    // 绔嬪嵆杩斿洖锛岄伩鍏嶉樆濉炰富绾跨▼
+    return true
+}
+
+/**
+ * 鍙戦�侀棬纾佺姸鎬佹秷鎭�
+ * @param {object} doorStatusData - 闂ㄧ鐘舵�佹暟鎹�
+ * @param {number} doorStatusData.status - 闂ㄧ鐘舵�侊紝0琛ㄧず闂ㄥ叧锛�1琛ㄧず闂ㄥ紑
+ * @param {string} doorStatusData.statusText - 闂ㄧ鐘舵�佹枃鏈�
+ * @param {number} doorStatusData.time - 鏃堕棿鎴�
+ */
+grainService.sendDoorStatusMessage = function(doorStatusData) {
+    // 浣跨敤setTimeout灏咹TTP璇锋眰鏀惧叆鍚庡彴鎵ц锛岄伩鍏嶉樆濉炰富绾跨▼
+    std.setTimeout(() => {
+        try {
+            // 纭繚URL鏍煎紡姝g‘锛屾坊鍔爃ttp://鍓嶇紑
+            let url = getHttpUrl()
+            if (!url.startsWith('http://') && !url.startsWith('https://')) {
+                url = 'http://' + url
+            }
+            
+            const timeout = 3000 // 3绉掕秴鏃�
+            
+            logger.info(`[grain]: 姝e湪鍙戦�侀棬纾佺姸鎬佹秷鎭�: ${url}`)
+            
+            // 鏋勫缓POST璇锋眰鏁版嵁
+                const postData = {
+                    sn: config.get("sys.sn") || " ", // 璁惧搴忓垪鍙凤紝浠庨厤缃腑鑾峰彇
+                    houseId: "0000", // 浠撳粧缂栫爜锛岄粯璁ゅ~鍏�"0000"
+                    outId: "0000", // 鑷畾涔夌紪鐮侊紝榛樿濉厖"0000"
+                    functionId: functionId.doorStatus, // 闂ㄧ鐘舵�佸姛鑳界爜
+                    timestamp: Date.now().toString(), // 鏃堕棿鎴�
+                    data: {
+                        doorStatus: doorStatusData.status // 闂ㄧ鐘舵��
+                    }
+                }
+            
+            logger.info(`[grain]: 鍙戦�侀棬纾佺姸鎬佹秷鎭暟鎹�: ${JSON.stringify(postData)}`)
+            
+            // 鍙戦�丠TTP POST璇锋眰
+            let response = http.post(url, postData, timeout)
+            
+            // 瑙f瀽鍝嶅簲鏁版嵁
+            if (typeof response === 'string') {
+                response = JSON.parse(response)
+            }
+            
+            if (response && response.body) {
+                let respData
+                try {
+                    respData = JSON.parse(response.body)
+                    logger.info(`[grain]: 闂ㄧ鐘舵�佹秷鎭搷搴�: ${JSON.stringify(respData)}`)
+                } catch (error) {
+                    logger.error(`[grain]: 瑙f瀽闂ㄧ鐘舵�佹秷鎭搷搴斿け璐�: ${error.message}`)
+                }
+            } else {
+                logger.info(`[grain]: 闂ㄧ鐘舵�佹秷鎭搷搴斾负绌篳)
+            }
+        } catch (error) {
+            logger.error(`[grain]: 鍙戦�侀棬纾佺姸鎬佹秷鎭け璐�: ${error.message}`)
+        }
+    }, 0)
+}
+
+// 鐩戝惉闂ㄧ鐘舵�佸彉鍖栦簨浠�
+bus.on('doorStatusChanged', (doorStatusData) => {
+    logger.info(`[grain]: 鎺ユ敹鍒伴棬纾佺姸鎬佸彉鍖栦簨浠�: ${JSON.stringify(doorStatusData)}`)
+    // 璋冪敤鍙戦�侀棬纾佺姸鎬佹秷鎭殑鍑芥暟
+    try {
+        if (typeof grainService.sendDoorStatusMessage === 'function') {
+            grainService.sendDoorStatusMessage(doorStatusData)
+        } else {
+            logger.error('[grain]: sendDoorStatusMessage 涓嶆槸涓�涓嚱鏁�')
+            logger.error('[grain]: grainService.sendDoorStatusMessage =', grainService.sendDoorStatusMessage)
+        }
+    } catch (error) {
+        logger.error('[grain]: 璋冪敤sendDoorStatusMessage鍑洪敊:', error.message)
+    }
+})
+
+export default grainService
\ No newline at end of file

--
Gitblit v1.9.3