news 2026/3/28 17:50:24

幽冥大陆(五十四)V10酒店门锁SDK 鸿蒙(HarmonyOS)——东方仙盟筑基期

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
幽冥大陆(五十四)V10酒店门锁SDK 鸿蒙(HarmonyOS)——东方仙盟筑基期

首先需要明确核心限制:

  1. 原 C# 代码依赖Windows 平台的本地 DLL 文件proRFLV102024.dll)实现硬件交互(读卡、发卡、蜂鸣器),而鸿蒙系统(尤其是鸿蒙设备端)无法直接调用 Windows DLL
  2. 鸿蒙设备端的硬件交互需通过鸿蒙的硬件访问 API(如 USB、外设驱动)厂商提供的鸿蒙版 SDK替代原 DLL 逻辑。

因此转换方案分为两部分:

  1. 保留核心业务逻辑(协议解析、发卡 / 注销逻辑、日志记录),用ArkTS(鸿蒙主流开发语言)实现;
  2. 对于硬件交互部分,提供鸿蒙设备端的硬件访问适配方案(标注需要替换的 DLL 调用逻辑)。

一、鸿蒙开发环境准备

  1. 安装DevEco Studio(鸿蒙官方 IDE);
  2. 创建鸿蒙项目(选择Stage 模型,基于 ArkTS);
  3. 若涉及硬件交互,需配置设备的硬件权限(如 USB 权限、外设访问权限)。

二、ArkTS 转换代码(鸿蒙设备端 / 服务端)

以下代码分为核心业务类鸿蒙 UI / 服务入口,保留原有的入住发卡、退房注销、读卡等核心逻辑,适配鸿蒙的 API 和语法。

1. 工具类:协议解析与日志记录(CyberWinUtil.ets

typescript

运行

/** * 模拟原C#的CyberWinAPPProtocolPackage协议解析类 * 对应鸿蒙的工具类 */ export class Cl_CyberWinAPPProtocolPackage { private data: Record<string, string> = {}; /** * 解析参数字符串(模拟原逻辑,可根据实际协议扩展) * @param param 参数字符串,格式如"hotelsign=123&lockno=456789" */ formatString(param: string): void { // 解析键值对参数(鸿蒙中可使用URLSearchParams简化) const params = new URLSearchParams(param); params.forEach((value, key) => { this.data[key] = value; }); } /** * 获取解析后的参数 * @param key 参数名 * @returns 参数值(空字符串表示无此参数) */ get(key: string): string { return this.data[key] || ''; } } /** * 日志工具类(适配鸿蒙的文件系统API) */ export class LogUtil { /** * 写入日志(对应原C#的write_log方法) * @param capturetype 日志分类 * @param type 日志类型 * @param content 日志内容 */ public static async writeLog(capturetype: string, type: string, content: string): Promise<void> { try { // 鸿蒙中获取应用沙箱路径(需申请文件权限:ohos.permission.WRITE_USER_STORAGE) const context = getContext(this); const logDir = `${context.filesDir}/log/${capturetype}/${new Date().toLocaleDateString('zh-CN').replace(/\//g, '-')}`; // 创建目录(鸿蒙的fileio API) const fileio = require('@ohos.fileio'); if (!fileio.accessSync(logDir)) { fileio.mkdirSync(logDir, { recursive: true }); } // 日志文件路径 const logPath = `${logDir}/${type}_log.log`; // 写入日志(追加模式) const logContent = `==============================\n${new Date().toLocaleString()}<<<<<<<<<<<<<<<<<<<<<<<<<<\n${content}\n\n`; fileio.writeFileSync(logPath, logContent, { flag: 'a', encoding: 'utf-8' }); } catch (e) { console.error(`写入日志失败:${e}`); } } } /** * 酒店标识解析工具类(对应原CyberWin_LocakAPP) */ export class CyberWinLocakAPP { /** * 解析酒店标识(对应原未来之窗_美萍_getsign方法) * @param bufCard 读卡缓冲区数据 * @returns 酒店标识或提示信息 */ public static getHotelSign(bufCard: Uint8Array): string { // 转换为ASCII字符串(对应原Encoding.ASCII.GetString) const cardStr = new TextDecoder('ascii').decode(bufCard); // 检查是否为空白卡 if (this.copy(bufCard, 25, 8) === 'FFFFFFFF') { console.log('此卡是空白卡,请换一张能开门的卡'); return '此卡是空白卡,请换一张能开门的卡'; } // 解析酒店标识(保留原逻辑) const s = this.copy(bufCard, 11, 4); let i = parseInt(s, 16) % 16384; const s2 = this.copy(bufCard, 9, 2); i = i + (parseInt(s, 16) * 65536); const i2 = parseInt(this.copy(bufCard, 9, 2), 16) * 65536 + parseInt(this.copy(bufCard, 11, 4), 16) % 16383; return i2.toString(); } /** * 字符串截取(对应原Copy方法) * @param buffer 数据缓冲区 * @param start 起始位置(从1开始) * @param length 截取长度 * @returns 截取后的字符串 */ private static copy(buffer: Uint8Array, start: number, length: number): string { const cardStr = new TextDecoder('ascii').decode(buffer); start = start < 1 ? 1 : start; return cardStr.substring(start - 1, start - 1 + length); } }

2. 核心业务类:酒店门锁逻辑(HotelDoorLock.ets

typescript

运行

import { Cl_CyberWinAPPProtocolPackage, LogUtil, CyberWinLocakAPP } from './CyberWinUtil'; /** * 酒店门锁核心业务类(对应原C#的APP类) * 鸿蒙中采用单例模式(可选) */ export class HotelDoorLock { private static instance: HotelDoorLock; private cardData: Uint8Array = new Uint8Array(128); // 对应原byte[128] private idPhotoSavePath: string = ''; public static bufCard: Uint8Array = new Uint8Array(128 + 1); // 读卡缓冲区 public static bufCardV10: Uint8Array = new Uint8Array(200 + 1); // V10读卡缓冲区 public static st: number = 0; // 状态码 // 单例模式(鸿蒙中常用) public static getInstance(): HotelDoorLock { if (!this.instance) { this.instance = new HotelDoorLock(); } return this.instance; } // -------------------------- 硬件交互适配(替换原DLL调用) -------------------------- /** * 初始化USB设备(对应原initializeUSB,鸿蒙中需替换为USB API) * @param fUSB 0=有驱USB,1=proUSB * @returns 0=成功,其他=失败 */ private initializeUSB(fUSB: number): number { // 【鸿蒙硬件适配】替换为鸿蒙的USB设备初始化逻辑 // 参考:https://developer.harmonyos.com/cn/docs/documentation/doc-references/usb_device-0000001524415869 // 示例:获取USB设备列表,打开指定设备 try { // 这里模拟返回成功,实际需对接硬件SDK return 0; } catch (e) { return -1; } } /** * 蜂鸣器控制(对应原Buzzer,鸿蒙中需替换为外设API) * @param fUSB USB标识 * @param t 蜂鸣时长(ms) * @returns 0=成功,其他=失败 */ private buzzer(fUSB: number, t: number): number { // 【鸿蒙硬件适配】替换为鸿蒙的蜂鸣器控制逻辑 // 若设备支持GPIO,可通过GPIO API控制蜂鸣器 console.log(`蜂鸣器响${t}ms`); return 0; } /** * 注销卡片(对应原CardErase,鸿蒙中需替换为硬件SDK) * @param fUSB USB标识 * @param hotelSign 酒店标识 * @param cardNo 卡号缓冲区 * @returns 0=成功,其他=失败 */ private cardErase(fUSB: number, hotelSign: number, cardNo: string): number { // 【鸿蒙硬件适配】替换为鸿蒙的卡片注销逻辑(调用硬件SDK) try { // 模拟返回成功 return 0; } catch (e) { return -1; } } /** * 发卡函数(对应原GuestCard_原始,鸿蒙中需替换为硬件SDK) * @param params 发卡参数 * @returns 0=成功,其他=失败 */ private guestCard(params: { fUSB: number, hotelSign: number, cardNo: number, dai: number, lockFlag: number, pdoors: number, openTime: string, closeTime: string, lockNo: string, cardData: string }): number { // 【鸿蒙硬件适配】替换为鸿蒙的发卡逻辑(调用硬件SDK) try { // 模拟返回成功 return 0; } catch (e) { return -1; } } /** * V10读卡(对应原rdCard_v10,鸿蒙中需替换为硬件SDK) * @returns true=成功,false=失败 */ private rdCardV10(): boolean { // 【鸿蒙硬件适配】替换为鸿蒙的读卡逻辑(调用硬件SDK) try { // 模拟读卡成功,写入缓冲区 HotelDoorLock.bufCardV10 = new Uint8Array(201).fill(0x30); // 模拟数据 HotelDoorLock.st = 0; return true; } catch (e) { HotelDoorLock.st = -1; console.error(`读卡失败:${e}`); return false; } } // -------------------------- 原业务方法实现 -------------------------- /** * 启动方法(对应原start) * @param obj 参数集合 * @returns 结果字符串 */ start(obj: Record<string, string>): string { const param1 = obj['param1'] || ''; return '随机预安装插件'; } /** * 设备状态检测(对应原status) * @param obj 参数集合 * @returns 结果字符串 */ status(obj: Record<string, string>): string { this.buzzer(1, 50); // 控制蜂鸣器 return '当你听到设备蜂鸣器,说明设备已经连接'; } /** * 退房注销卡片(对应原checkingout) * @param obj 参数集合 * @returns 结果字符串 */ checkingout(obj: Record<string, string>): string { let result = '注销卡片'; const param = obj['param'] || ''; // 解析协议参数 const clApp = new Cl_CyberWinAPPProtocolPackage(); clApp.formatString(param); const hotelSign = clApp.get('hotelsign'); if (!hotelSign) { return `${result}:酒店标识为空`; } // 初始化USB设备 const usbStatus = this.initializeUSB(1); if (usbStatus !== 0) { console.log('设备打开失败'); return '打开端口失败'; } // 调用注销卡片函数 const cardNo = ''; // 模拟卡号 const st = this.cardErase(1, parseInt(hotelSign), cardNo); if (st !== 0) { result += `:注销失败${st}`; } else { result += ':成功'; } // 写入日志 LogUtil.writeLog('hotel', 'checkout', result); return result; } /** * 入住发卡(对应原checkingin) * @param obj 参数集合 * @returns 结果字符串 */ checkingin(obj: Record<string, string>): string { let result = '酒店入住发卡'; const param = obj['param'] || ''; // 解析协议参数 const clApp = new Cl_CyberWinAPPProtocolPackage(); clApp.formatString(param); const lockNo = clApp.get('lockno'); const hotelSign = clApp.get('hotelsign'); const closeTime = clApp.get('checkingouttime'); // 校验锁号长度 if (lockNo.length < 6) { LogUtil.writeLog('hotel', 'checkin', `锁号长度错误=${lockNo}`); return `${result}:锁号长度错误`; } // 初始化USB设备 const usbStatus = this.initializeUSB(1); if (usbStatus !== 0) { console.log('设备打开失败'); return '打开端口失败'; } // 构造发卡参数 const openTime = new Date().toLocaleString('zh-CN', { year: '2-digit', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', }).replace(/[^\d]/g, ''); // 格式:yyMMddHHmmss const lockFlag = 1; // 反锁标志 const dai = 1; // 房间类型标识 // 调用发卡函数 const st = this.guestCard({ fUSB: 1, hotelSign: parseInt(hotelSign), cardNo: 0, dai: dai, lockFlag: lockFlag, pdoors: 0, openTime: openTime, closeTime: closeTime, lockNo: lockNo, cardData: '' }); if (st !== 0) { result += '调用发卡函数失败'; } else { result += `制卡成功V2024${lockNo}`; } // 写入日志 LogUtil.writeLog('hotel', 'checkin', result); return result; } /** * 读取酒店标识(对应原getsign) * @param obj 参数集合 * @returns 酒店标识或提示信息 */ getsign(obj: Record<string, string>): string { // 读卡 if (!this.rdCardV10()) { LogUtil.writeLog('hotel', 'getsign', '读卡失败'); return '读卡失败'; } // 解析酒店标识 const hotelSign = CyberWinLocakAPP.getHotelSign(HotelDoorLock.bufCardV10); LogUtil.writeLog('hotel', 'getsign', `酒店标识:${hotelSign}`); return hotelSign; } }

3. 鸿蒙 UI 页面:调用示例(Index.ets

typescript

运行

@Entry @Component struct HotelDoorLockPage { private hotelLock = HotelDoorLock.getInstance(); @State result: string = ''; build() { Column() { Text('酒店门锁控制') .fontSize(30) .fontWeight(FontWeight.Bold) .margin({ bottom: 20 }); // 状态检测按钮 Button('检测设备状态') .onClick(() => { this.result = this.hotelLock.status({}); }) .margin({ bottom: 10 }); // 退房注销按钮 Button('退房注销卡片') .onClick(() => { // 模拟参数:hotelsign=123456 this.result = this.hotelLock.checkingout({ param: 'hotelsign=123456' }); }) .margin({ bottom: 10 }); // 入住发卡按钮 Button('入住发卡') .onClick(() => { // 模拟参数:hotelsign=123456&lockno=123456&checkingouttime=2501010000 this.result = this.hotelLock.checkingin({ param: 'hotelsign=123456&lockno=123456&checkingouttime=2501010000' }); }) .margin({ bottom: 10 }); // 读取酒店标识按钮 Button('读取酒店标识') .onClick(() => { this.result = this.hotelLock.getsign({}); }) .margin({ bottom: 10 }); // 结果显示 Text(this.result) .fontSize(16) .margin({ top: 20 }) .textAlign(TextAlign.Center); } .width('100%') .height('100%') .padding(20) .justifyContent(FlexAlign.Center); } }

三、关键代码解释

  1. 硬件交互适配:原 C# 的 DLL 调用逻辑被替换为鸿蒙硬件 API 的适配层,标注了需要对接的鸿蒙 USB / 外设 API(如 USB 设备初始化、蜂鸣器控制),实际使用时需根据硬件厂商提供的鸿蒙 SDK 替换。
  2. 业务逻辑保留:原有的协议解析、参数校验、发卡 / 注销、日志记录等逻辑完全保留,仅适配 ArkTS 的语法和鸿蒙的 API(如fileio写日志、TextDecoder处理字符编码)。
  3. 鸿蒙特性适配:采用鸿蒙的单例模式声明式 UI,结合@Entry@Component装饰器实现 UI 与业务逻辑的分离。

四、鸿蒙硬件交互补充说明

如果需要在鸿蒙设备上实现真实的硬件交互(读卡、发卡),需:

  1. 申请硬件权限:在module.json5中配置 USB、外设等权限(如ohos.permission.USB_DEVICE);
  2. 对接硬件 SDK:联系硬件厂商获取鸿蒙版的门锁 SDK(替代原 Windows DLL);
  3. 使用鸿蒙硬件 API:参考鸿蒙官方文档的USB 设备开发、GPIO 开发等文档。

阿雪技术观


让我们积极投身于技术共享的浪潮中,不仅仅是作为受益者,更要成为贡献者。无论是分享自己的代码、撰写技术博客,还是参与开源项目的维护和改进,每一个小小的举动都可能成为推动技术进步的巨大力量

Embrace open source and sharing, witness the miracle of technological progress, and enjoy the happy times of humanity! Let's actively join the wave of technology sharing. Not only as beneficiaries, but also as contributors. Whether sharing our own code, writing technical blogs, or participating in the maintenance and improvement of open source projects, every small action may become a huge force driving technological progrss

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/27 16:46:40

Langchain-Chatchat与Jaeger分布式追踪系统集成

Langchain-Chatchat 与 Jaeger 分布式追踪集成实践 在企业级 AI 应用日益复杂的今天&#xff0c;一个看似简单的“提问-回答”交互背后&#xff0c;可能隐藏着数十个模块的协同工作&#xff1a;文档解析、文本切片、向量检索、上下文拼接、模型推理……当这套流程部署在本地环境…

作者头像 李华
网站建设 2026/3/13 8:36:11

账号总被盯上?Open-AutoGLM安全加固9大实操技巧,现在不做就晚了

第一章&#xff1a;Open-AutoGLM账号安全现状与威胁分析近年来&#xff0c;随着自动化大语言模型&#xff08;AutoGLM&#xff09;平台的广泛应用&#xff0c;Open-AutoGLM作为开源社区中的重要组成部分&#xff0c;其账号安全问题日益凸显。大量开发者依赖该平台进行模型训练、…

作者头像 李华
网站建设 2026/3/28 11:56:58

Langchain-Chatchat问答系统故障自愈机制设计探索

Langchain-Chatchat 问答系统故障自愈机制设计探索 在企业级 AI 应用日益普及的今天&#xff0c;一个看似简单的“智能问答”背后&#xff0c;往往隐藏着复杂的系统工程挑战。比如&#xff0c;当你在公司内部知识库中输入“如何申请差旅报销&#xff1f;”时&#xff0c;期望的…

作者头像 李华
网站建设 2026/3/20 8:58:36

Langchain-Chatchat问答系统压力测试报告:千人并发下的稳定性表现

Langchain-Chatchat问答系统压力测试报告&#xff1a;千人并发下的稳定性表现 在企业智能化转型的浪潮中&#xff0c;知识管理正从静态文档库向动态智能服务演进。越来越多的企业希望构建专属的AI助手&#xff0c;既能理解内部制度、产品手册和业务流程&#xff0c;又能以自然语…

作者头像 李华
网站建设 2026/3/22 5:58:09

Java毕设选题推荐:基于SpringBoot+Vue采购管理系统的设计与实基于springboot的政府集中采购管理系统设计与实现的设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华