微信小程序藍牙連接打印機打印單據完整Demo【藍牙小票打印】

文章目錄

  • 一、準備工作
    • 1. 硬件準備
    • 2. 開發環境
  • 二、小程序配置
    • 1. 修改app.json
  • 三、完整代碼實現
    • 1. pages/index/index.wxml
    • 2. pages/index/index.wxss
    • 3. pages/index/index.js
  • 四、ESC/POS指令說明
  • 五、測試流程
  • 六、常見問題解決
  • 七、進一步優化建議


在這里插入圖片描述

下面我將提供一個完整的微信小程序通過藍牙連接熱敏打印機(支持ESC/POS指令)打印訂單小票的詳細實現方案。本教程假設您使用的是常見的藍牙熱敏打印機(如佳博、芯燁等品牌)。

一、準備工作

1. 硬件準備

  • 藍牙熱敏小票打印機(支持 ESC/POS 指令)
  • 確保打印機已充電/通電
  • 知道打印機的藍牙名稱(如"GBTP-XXXX")

2. 開發環境

  • 微信開發者工具
  • 已注冊微信小程序賬號
  • 小程序已開通藍牙權限(在 app.json 中配置)

二、小程序配置

1. 修改app.json

{"pages": ["pages/index/index"],"permission": {"scope.userLocation": {"desc": "你的位置信息將用于藍牙設備搜索"}},"requiredPrivateInfos": ["getLocation", "chooseAddress", "startBluetoothDevicesDiscovery"]
}

三、完整代碼實現

1. pages/index/index.wxml

<view class="container"><button bindtap="searchPrinter">搜索藍牙打印機</button><view wx:for="{{devices}}" wx:key="deviceId"><view class="device-item" bindtap="connectPrinter" data-device="{{item}}">{{item.name}} ({{item.deviceId}})</view></view><button bindtap="printTest" disabled="{{!connected}}">打印測試小票</button><button bindtap="printOrder" disabled="{{!connected}}">打印訂單</button><view class="status">狀態: {{status}}</view>
</view>

2. pages/index/index.wxss

.container {padding: 20px;
}.device-item {padding: 15px;border-bottom: 1px solid #eee;
}button {margin-top: 15px;
}.status {margin-top: 20px;color: #666;font-size: 14px;
}

3. pages/index/index.js

Page({data: {devices: [],         // 搜索到的設備列表connected: false,    // 是否已連接deviceId: '',        // 當前連接的設備IDserviceId: '',       // 藍牙服務UUIDcharacteristicId: '', // 藍牙特征值UUIDstatus: '未連接',     // 狀態提示orderInfo: {         // 示例訂單數據orderNo: '20231115001',date: '2023-11-15 14:30',items: [{name: '有機青菜', price: 12.5, quantity: 2},{name: '新鮮番茄', price: 8.0, quantity: 3},{name: '優質土豆', price: 5.5, quantity: 1}],total: 47.5,address: '北京市朝陽區科技園A座1001室',phone: '138****1234'}},// 搜索藍牙設備searchPrinter() {this.setData({status: '正在搜索藍牙設備...'});// 初始化藍牙模塊wx.openBluetoothAdapter({success: (res) => {console.log('藍牙適配器初始化成功', res);this.startDiscovery();},fail: (err) => {console.error('藍牙適配器初始化失敗', err);this.setData({status: '藍牙初始化失敗,請檢查手機藍牙是否開啟'});}});},// 開始搜索設備startDiscovery() {wx.startBluetoothDevicesDiscovery({allowDuplicatesKey: false,success: (res) => {console.log('開始搜索設備', res);this.setData({status: '正在搜索設備...'});// 監聽找到新設備事件wx.onBluetoothDeviceFound((res) => {const devices = res.devices.filter(device => device.name && device.name.indexOf('GBTP') !== -1);if (devices.length > 0) {this.setData({devices: devices,status: `找到${devices.length}個打印機設備`});wx.stopBluetoothDevicesDiscovery(); // 找到設備后停止搜索}});},fail: (err) => {console.error('搜索設備失敗', err);this.setData({status: '搜索設備失敗'});}});},// 連接打印機connectPrinter(e) {const device = e.currentTarget.dataset.device;this.setData({status: `正在連接${device.name}...`});// 連接設備wx.createBLEConnection({deviceId: device.deviceId,success: (res) => {console.log('設備連接成功', res);this.setData({deviceId: device.deviceId,status: `已連接${device.name}`});this.getBLEDeviceServices(device.deviceId);},fail: (err) => {console.error('設備連接失敗', err);this.setData({status: '連接失敗'});}});},// 獲取藍牙服務getBLEDeviceServices(deviceId) {wx.getBLEDeviceServices({deviceId: deviceId,success: (res) => {console.log('獲取服務成功', res.services);for (const service of res.services) {// 通常藍牙打印機的服務UUID是FF00或FFE0if (service.uuid.startsWith('FFE0') || service.uuid.startsWith('FF00')) {this.setData({serviceId: service.uuid});this.getBLEDeviceCharacteristics(deviceId, service.uuid);break;}}},fail: (err) => {console.error('獲取服務失敗', err);}});},// 獲取藍牙特征值getBLEDeviceCharacteristics(deviceId, serviceId) {wx.getBLEDeviceCharacteristics({deviceId: deviceId,serviceId: serviceId,success: (res) => {console.log('獲取特征值成功', res.characteristics);for (const characteristic of res.characteristics) {// 尋找可寫的特征值if (characteristic.properties.write) {this.setData({characteristicId: characteristic.uuid,connected: true});console.log('打印機已準備好');break;}}},fail: (err) => {console.error('獲取特征值失敗', err);}});},// 打印測試小票printTest() {this.setData({status: '正在打印測試小票...'});// ESC/POS指令const buffer = new ArrayBuffer(100);const dataView = new Uint8Array(buffer);// 初始化打印機dataView[0] = 0x1B;dataView[1] = 0x40;// 設置居中dataView[2] = 0x1B;dataView[3] = 0x61;dataView[4] = 0x01;// 設置字體大小dataView[5] = 0x1D;dataView[6] = 0x21;dataView[7] = 0x11;// 打印文本const text = "測試小票\n";for (let i = 0; i < text.length; i++) {dataView[8 + i] = text.charCodeAt(i);}// 換行const lineBreak = "\n\n\n\n";for (let i = 0; i < lineBreak.length; i++) {dataView[8 + text.length + i] = lineBreak.charCodeAt(i);}// 切紙dataView[8 + text.length + lineBreak.length] = 0x1D;dataView[9 + text.length + lineBreak.length] = 0x56;dataView[10 + text.length + lineBreak.length] = 0x42;dataView[11 + text.length + lineBreak.length] = 0x00;// 發送數據this.writeBLECharacteristicValue(buffer);},// 打印訂單printOrder() {this.setData({status: '正在打印訂單...'});// 創建緩沖區const commands = [];// 初始化打印機commands.push(0x1B, 0x40);// 設置居中commands.push(0x1B, 0x61, 0x01);// 設置大字體commands.push(0x1D, 0x21, 0x11);// 打印標題this.addTextToCommand(commands, "蔬菜配送訂單\n");// 恢復默認字體commands.push(0x1D, 0x21, 0x00);// 訂單信息this.addTextToCommand(commands, `訂單號: ${this.data.orderInfo.orderNo}\n`);this.addTextToCommand(commands, `日期: ${this.data.orderInfo.date}\n\n`);// 商品列表this.addTextToCommand(commands, "----------------------------\n");this.addTextToCommand(commands, "商品名稱   單價  數量  小計\n");this.addTextToCommand(commands, "----------------------------\n");this.data.orderInfo.items.forEach(item => {const line = `${item.name}    ${item.price}   ${item.quantity}   ${(item.price * item.quantity).toFixed(2)}\n`;this.addTextToCommand(commands, line);});this.addTextToCommand(commands, "----------------------------\n");this.addTextToCommand(commands, `總計: ¥${this.data.orderInfo.total}\n\n`);// 配送信息this.addTextToCommand(commands, `配送地址: ${this.data.orderInfo.address}\n`);this.addTextToCommand(commands, `聯系電話: ${this.data.orderInfo.phone}\n\n`);// 感謝語commands.push(0x1B, 0x61, 0x01); // 居中this.addTextToCommand(commands, "感謝您的惠顧!\n");this.addTextToCommand(commands, "期待再次為您服務\n\n\n");// 切紙commands.push(0x1D, 0x56, 0x42, 0x00);// 轉換為ArrayBufferconst buffer = new ArrayBuffer(commands.length);const dataView = new Uint8Array(buffer);commands.forEach((value, index) => {dataView[index] = value;});// 發送數據this.writeBLECharacteristicValue(buffer);},// 輔助方法:添加文本到命令數組addTextToCommand(commands, text) {for (let i = 0; i < text.length; i++) {commands.push(text.charCodeAt(i));}},// 寫入藍牙特征值writeBLECharacteristicValue(buffer) {wx.writeBLECharacteristicValue({deviceId: this.data.deviceId,serviceId: this.data.serviceId,characteristicId: this.data.characteristicId,value: buffer,success: (res) => {console.log('寫入成功', res);this.setData({status: '打印指令已發送'});},fail: (err) => {console.error('寫入失敗', err);this.setData({status: '打印失敗'});}});}
});

四、ESC/POS指令說明

  1. 打印機初始化:0x1B 0x40

  2. 設置對齊方式

    • 左對齊:0x1B 0x61 0x00
    • 居中:0x1B 0x61 0x01
    • 右對齊:0x1B 0x61 0x02
  3. 設置字體大小

    • 0x1D 0x21 0x00 - 正常大小
    • 0x1D 0x21 0x11 - 雙倍寬高
  4. 換行0x0A

  5. 切紙0x1D 0x56 0x42 0x00

五、測試流程

  1. 打開微信開發者工具,導入本項目
  2. 點擊"搜索藍牙打印機"按鈕
  3. 在設備列表中找到您的打印機并點擊連接
  4. 連接成功后,點擊"打印測試小票"測試基本功能
  5. 點擊"打印訂單"打印完整的訂單信息

六、常見問題解決

  1. 找不到設備:

    • 確保打印機藍牙已開啟并可被發現
    • 檢查打印機是否支持 BLE (藍牙4.0及以上)
    • 修改代碼中的設備名稱過濾條件(如GBTP)
  2. 連接失敗:

    • 確保打印機未被其他設備連接
    • 嘗試重啟打印機藍牙
  3. 打印亂碼:

    • 檢查 ESC/POS 指令是否正確
    • 確保打印機支持接收的指令集
  4. 權限問題:

    • 確保小程序已獲取藍牙相關權限
    • 在手機上授權小程序使用藍牙

七、進一步優化建議

  1. 添加打印機斷開重連機制
  2. 實現打印任務隊列,防止并發打印沖突
  3. 根據打印機型號調整指令集
  4. 添加打印狀態回調,提供更好的用戶反饋
  5. 實現打印內容模板化,便于維護

這個 Demo 提供了完整的藍牙連接和打印功能實現,您可以根據實際需求進行調整和擴展。實際開發中,建議參考您使用的打印機型號的特定指令集文檔進行微調。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/902849.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/902849.shtml
英文地址,請注明出處:http://en.pswp.cn/news/902849.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ubuntu opencv 安裝

1.ubuntu opencv 安裝 在Ubuntu系統中安裝OpenCV&#xff0c;可以通過多種方式進行&#xff0c;以下是一種常用的安裝方法&#xff0c;包括從源代碼編譯安裝。請注意&#xff0c;安裝步驟可能會因OpenCV的版本和Ubuntu系統的具體版本而略有不同。 一、安裝準備 更新系統&…

【C++】class靜態常量

Usage: static const T 1 background static const成員屬于類&#xff0c;而不是類的實例&#xff0c;所以它們的初始化需要在類外進行(或者在C17之后可以用inline初始化)。 使用中可能遇到的情況&#xff1a; 在頭文件中聲明一個static const成員&#xff0c;然后在多個cpp…

Java 安全:如何防止 DDoS 攻擊?

一、DDoS 攻擊簡介 DDoS&#xff08;分布式拒絕服務&#xff09;攻擊是一種常見的網絡攻擊手段&#xff0c;攻擊者通過控制大量的僵尸主機向目標服務器發送海量請求&#xff0c;致使服務器資源耗盡&#xff0c;無法正常響應合法用戶請求。在 Java 應用開發中&#xff0c;了解 …

統計文件中單詞出現的次數并累計

# 統計單詞出現次數 fileopen("E:\Dasktape/python_test.txt","r",encoding"UTF-8") f1file.read() # 讀取文件 countf1.count("is") # 統計文件中is 單詞出現的次數 print(f"此文件中單詞is出現了{count}次")# 2.判斷單詞出…

C語言實現貪心算法

一、貪心算法核心思想 特征&#xff1a;在每一步選擇中都采取當前狀態下最優&#xff08;局部最優&#xff09;的選擇&#xff0c;從而希望導致全局最優解 適用場景&#xff1a;需要滿足貪心選擇性質和最優子結構性質 二、經典貪心算法示例 1. 活動選擇問題 目標&#xff1a…

《一文讀懂Transformers庫:開啟自然語言處理新世界的大門》

《一文讀懂Transformers庫:開啟自然語言處理新世界的大門》 GitHub - huggingface/transformers: ?? Transformers: State-of-the-art Machine Learning for Pytorch, TensorFlow, and JAX. HF-Mirror Hello! Transformers快速入門 pip install transformers -i https:/…

Vue里面elementUi-aside 和el-main不垂直排列

先說解決方法 main.js少導包 import element-ui/lib/theme-chalk/index.css; //加入此行即可 問題復現 排查了一個小時終于找出來問題了&#xff0c;建議導包去看官方的文檔&#xff0c;作者就是因為看了別人的導包流程導致的問題 導包官網地址Element UI導包快速入門

MYSQL 常用字符串函數 和 時間函數詳解

一、字符串函數 1、?CONCAT(str1, str2, …) 拼接多個字符串。 SELECT CONCAT(Hello, , World); -- 輸出 Hello World2、SUBSTRING(str, start, length)?? 或 ?SUBSTR() 截取字符串。 SELECT SUBSTRING(MySQL, 3, 2); -- 輸出 SQ3、LENGTH(str)?? 與 ?CHAR_LENGTH…

Python-Agent調用多個Server-FastAPI版本

Python-Agent調用多個Server-FastAPI版本 Agent調用多個McpServer進行工具調用 1-核心知識點 fastAPI的快速使用agent調用多個server 2-思路整理 1&#xff09;先把每個子服務搭建起來2&#xff09;再暴露一個Agent 3-參考網址 VSCode配置Python開發環境&#xff1a;https:/…

Drools+自定義規則庫

文章目錄 前言一、創建規則庫二、SpringBootDrools程序1.Maven依賴2.application.yml3.Mapper.xml4.Drools配置類5.Service6.Contoller7.測試接口 前言 公司的技術方案想搭建Drools自定義規則庫配合大模型進行數據的校驗。本篇用來記錄使用SpringBoot配合Drools開發Demo程序。…

潮了 低配電腦6G顯存生成60秒AI視頻 本地部署/一鍵包/云算力部署/批量生成

最近發現了一個讓人眼前一亮的工具——FramePack&#xff0c;它能用一塊普通的6GB顯存筆記本GPU&#xff0c;生成60秒電影級的高清視頻畫面&#xff0c;效果堪稱炸裂&#xff01;那么我們就把他本地部署起來玩一玩、下載離線一鍵整合包&#xff0c;或者是用云算力快速上手。接下…

【藍橋杯選拔賽真題104】Scratch回文數 第十五屆藍橋杯scratch圖形化編程 少兒編程創意編程選拔賽真題解析

目錄 scratch回文數 一、題目要求 1、準備工作 2、功能實現 二、案例分析 1、角色分析 2、背景分析 3、前期準備 三、解題思路 四、程序編寫 五、考點分析 六、推薦資料 1、scratch資料 2、python資料 3、C++資料 scratch回文數 第十五屆青少年藍橋杯scratch編…

大廠面試-框架篇

前言 本章內容來自B站黑馬程序員java大廠面試題和小林coding 博主學習筆記&#xff0c;如果有不對的地方&#xff0c;海涵。 如果這篇文章對你有幫助&#xff0c;可以點點關注&#xff0c;點點贊&#xff0c;謝謝你&#xff01; 1.Spring 1.1 Spring框架中的單例bean是線程…

【AI 加持下的 Python 編程實戰 2_10】DIY 拓展:從掃雷小游戲開發再探問題分解與 AI 代碼調試能力(中)

文章目錄 DIY 實戰&#xff1a;從掃雷小游戲開發再探問題分解能力3 問題分解實戰&#xff08;自頂向下&#xff09;3.2 頁面渲染邏輯3.3 事件綁定邏輯 4 代碼實現&#xff08;自底向上&#xff09;4.1 頁面渲染部分4.2 事件綁定部分 寫在前面 本篇將利用《Learn AI-assisted Py…

微信小程序開發1------微信小程序中的消息提示框總結

微信小程序中的消息提示框主要分為以下幾種&#xff1a; 1. wx.showToast(Object object) 功能&#xff1a; 顯示消息提示框&#xff0c;一般用于顯示操作結果、狀態等。 特點&#xff1a; 提示框顯示在屏幕中間&#xff0c;持續一段時間后自動消失&#xff08;默認1.5秒&…

AI 場景落地:API 接口服務 VS 本地部署,哪種更適合?

在當前 AI 技術迅猛發展的背景下&#xff0c;企業在實現 AI 場景落地時&#xff0c;面臨著一個關鍵抉擇&#xff1a;是選擇各大廠商提供的 API 接口服務&#xff0c;還是進行本地化部署&#xff1f;這不僅關乎成本、性能和安全性&#xff0c;還涉及到技術架構、數據治理和長期戰…

Android 加殼應用運行流程 與 生命周期類處理方案

版權歸作者所有&#xff0c;如有轉發&#xff0c;請注明文章出處&#xff1a;https://cyrus-studio.github.io/blog/ DexClassLoader DexClassLoader 可以加載任意路徑下的 dex&#xff0c;或者 jar、apk、zip 文件&#xff08;包含classes.dex&#xff09;。常用于插件化、熱…

c++進階——類與繼承

文章目錄 繼承繼承的基本概念繼承的基本定義繼承方式繼承的一些注意事項 繼承類模板 基類和派生類之間的轉換繼承中的作用域派生類的默認成員函數默認構造函數拷貝構造賦值重載析構函數默認成員函數總結 不能被繼承的類繼承和友元繼承與靜態成員多繼承及其菱形繼承問題繼承模型…

GAEA情感坐標背后的技術原理

基于GAEA的去中心化物理基礎設施網絡&#xff08;DePIN&#xff09;&#xff0c;用戶有機會在GAEA平臺上獲得寶貴的數據共享積分。為了提升這些洞察的豐富性&#xff0c;用戶必須花費一定數量的積分&#xff0c;將過去的網絡數據與當前的情感數據綁定&#xff0c;從而產生一種新…

圖形編輯器基于Paper.js教程27:對圖像描摹的功能實現,以及參數調整

本篇文章來講一下 圖像描摹的功能的實現。 我們知道要雕刻圖片可以通過分析圖片的像素來生成相應的gcode進行雕刻&#xff0c;但如果你想要將圖片轉換為線稿進行雕刻&#xff0c;這個時候就要從圖片中提取出 線稿。 例如下面的圖片&#xff1a; 你想要獲取到這個圖片的線稿&…