当前位置:网站首页>Real project, realized by wechat applet opening code (end)
Real project, realized by wechat applet opening code (end)
2022-07-07 02:22:00 【Hua Weiyun】
Hello everyone , Welcome to [ Artie, talk about it ] Blog
In the previous article 《 Wechat applet realizes Bluetooth door opening ( One )》 We have done a detailed technical design , Now this article mainly talks about how to code and realize .
If readers want to know how the applet calls the Bluetooth door opening part , You can click [ Small program function realization ] Jump .
@[toc]
As a software that needs to be written by both front and back ends , I'm used to starting from the back end , The back end starts with the database .
Create a table structure
about Mysql database , I chose the cloud database that has been installed before , You can also install locally , Please refer to other documents for the installation tutorial .
![ Insert picture description here ](https://img-blog.csdnimg.cn/9e091b377e95434dbb02b319c9fde217.png#pic_center =300x)
When you create a database , Select code as utf8mb4, Because this code can save some special emoticon characters .
To make this code work properly , First, through SHOW VARIABLES LIKE '%char%';
Check character_set_server
Whether it is utf8mb4, If it doesn't need to be modified my.cnf The configuration file , Invalid command modification .
Because the table structure has been designed in the previous article , No more repetition here , Here is the created table .
Create a back-end service
Because this software is used , The back-end requirements are not very high , You only need to authenticate the account , therefore SpringBoot Monomer application is enough .
Use Spring Initializr Create a Spring Boot application
![ Insert picture description here ](https://img-blog.csdnimg.cn/79572dfe7a7d4564ac432b7624208976.png#pic_center =600x)
Code directory structure
admin - Manage background related interface services
api - The front end of the applet calls the relevant interface services
common - Public tools 、 Constant etc.
config - Web Related configuration files ,Shiro、FreeMarker etc.
Management background function realization
Before introducing specific functions , It is necessary to introduce several important public classes :pom.xml:
maven To configure BaseController:
Public Controller, Built in some public methods
For space , When introducing the implementation of function coding , I will choose the important part to introduce , Please download the source code for the parts not introduced
pom.xml To configure
So that readers can easily understand , Here is the finished pom To configure .
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.mini</groupId> <artifactId>bluetooth</artifactId> <version>0.0.1-SNAPSHOT</version> <name>bluetooth-admin</name> <description> Wechat applet back end </description> <properties> <java.version>11</java.version> <shiro.version>1.3.2</shiro.version> <mysql.version>8.0.11</mysql.version> <fastjson.version>1.2.58</fastjson.version> <druid.version>1.1.9</druid.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.3</version> <exclusions> <exclusion> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>net.178le</groupId> <artifactId>shiro-freemarker-tags</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId>com.xiaoleilu</groupId> <artifactId>hutool-all</artifactId> <version>3.0.7</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build></project>
spring-boot-starter-freemarker:
freemarker rely on spring-boot-starter-web:
web rely on spring-boot-starter-aop:
aop rely on , When logging pagehelper-spring-boot-starter:
Paging plug-ins , The interior already contains mybatis rely on shiro-core、shiro-spring:
shiro Dependence mysql-connector-java:
mysql rely on shiro-freemarker-tags:
shiro Of freemarker Tags depend on , You can use... On the page shiro label , In order to control permissions druid:
Database connection pool dependency fastjson:
json rely on hutool-all:
The toolkit depends on
BaseController
/** * Foundation class , therefore controller Should inherit this class * */public class BaseController { /** * Some request header formats are defined */ public static final String TEXT_UTF8 = "text/html;charset=UTF-8"; public static final String JSON_UTF8 = "application/json;charset=UTF-8"; public static final String XML_UTF8 = "application/xml;charset=UTF-8"; /** * Defines the common request method name , It is convenient for some unified operations */ public static final String LIST = "list"; public static final String VIEW = "view"; public static final String ADD = "add"; public static final String SAVE = "save"; public static final String EDIT = "edit"; public static final String UPDATE = "update"; public static final String DELETE = "delete"; public static final String PAGE = "page"; @Autowired protected HttpServletRequest request; @Autowired protected HttpSession session; protected UserVO currentUser(){ // use SecurityUtils.getSubject().getSession() You can also get session UserVO userVO = (UserVO) session.getAttribute(Constants.SESSION_KEY); return userVO; } public static String redirect(String format, Object... arguments) { return new StringBuffer("redirect:").append(MessageFormat.format(format, arguments)).toString(); }}
It's defined here Common request formats 、 Commonly used request method name , It is convenient for unified operation , Like intercepting 、 A method to get the current user name ; Jump string splicing method
Special : Get the method of the current user , This is through HttpSession To get , It can also be used. SecurityUtils.getSubject().getSession()
Get session
Login and logout function
User input http://host/admin
or http://host/admin/login
After that, you can jump to the login page .
When logging in , Wrong account password
, Prompt required : The user name or password is incorrect or disabled
, Do not prompt specific errors , To prevent exhaustive speculation .
When you log out , You need to clear the user login information , And can jump to the login page
@RestController@RequestMapping("/admin/")public class IndexController extends BaseController { @Autowired private ResourceService resourceService; @Autowired private UserService userService; /** * Login page Jump */ @GetMapping("") public void index(){ } /** * Login page Jump */ @GetMapping(value="login") public void login(){ } /** * Login interface * @param userVO * @return */ @PostMapping(value="login") public Result<String> loginSubmit(UserVO userVO) { Subject subject = SecurityUtils.getSubject(); userVO.setPassword(userVO.getPassword()); UsernamePasswordToken token = new UsernamePasswordToken(userVO.getUsername(), userVO.getPassword()); try { // call shiro Sign in subject.login(token); // Yes shiro Exception handling , The front end displays different exceptions }catch (UnknownAccountException e) { return new Result<>(ResultEnum.USERNAME_PASSWORD_ERROR); } catch (IncorrectCredentialsException e) { return new Result<>(ResultEnum.USERNAME_PASSWORD_ERROR); }catch (LockedAccountException e){ return new Result<>(ResultEnum.USER_HAS_LOCKER); }catch (AuthenticationException e) { return new Result<>(ResultEnum.OTHER_ERROR); } // Log in successfully and jump to the home page userVO.setLastLoginTime(new Date()); userVO.setLoginIp(subject.getSession().getHost()); userService.updateByUserName(userVO); return new Result<>("/admin/index"); } /** * home page * @param modelMap * @return */ @GetMapping(value = "index") public String index(ModelMap modelMap) { UserVO userVO = currentUser(); String resourceId = userVO.getResourceIds(); List<ResourceVO> result = resourceService.findById(resourceId); modelMap.put("list",result); modelMap.put("bean",userVO); return "admin/index"; } /** * sign out * @return */ @GetMapping(value = "logout") public String logout() { Subject subject = SecurityUtils.getSubject(); subject.logout(); return "admin/login"; }}
@GetMapping("")
Just type http://host/admin Jump through this interface ,freemark Default will jump to admin/index route , If the method of this path detects that there is no login, it will jump to login The login page
@GetMapping(value="login")
Input http://host/admin/login Then jump to the login page ,freemark Will automatically locate to login.ftl page
@PostMapping(value="login")
Here are a few steps to explain :
- Enter the user name and password and click login , The front end requests this interface
- The front end needs to set the password MD5 Encrypted and transmitted to the back end , Create a with a username and password UsernamePasswordToken token , Pass a token into SecurityUtils.getSubject() Acquired Subject Of login Method
- This method throws AuthenticationException The authentication is abnormal , Catch the corresponding exception , And convert it into a custom exception and feed it back to the front end
- Subject Of login After the method is processed successfully , Login time , Sign in ip Update to user information
- Return to jump back to the home page address
@GetMapping(value = "index")
Background home page address , This method will obtain the current login user information and the permissions that the user has , Deposit in ModelMap in , For front-end display
@GetMapping(value = "logout")
Background logout interface , This method will clear the status information of the currently logged in user , And jump to the login page
PM: 2022 year 6 month 30 Japan 01:01:41
shiro For login authentication management , There is an important class UserRealm, It is responsible for the user's authority and identity verification function .
/** * authentication */@Componentpublic class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String)principals.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); Session session = SecurityUtils.getSubject().getSession(); UserVO userVO = (UserVO) session.getAttribute(Constants.SESSION_KEY); authorizationInfo.setRoles(userVO.getRoles()); Set<String> permissions = userVO.getPermissions(); if (username.equals("admin")){ permissions.add("*:*"); } authorizationInfo.setStringPermissions(permissions); return authorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String userno = (String) authenticationToken.getPrincipal(); String password = new String((char[]) authenticationToken.getCredentials()); Result<UserVO> result = userService.login(userno, password); if (result.isSuccess()){ UserVO userVO = result.getData(); Session session = SecurityUtils.getSubject().getSession(); session.setAttribute(Constants.SESSION_KEY,userVO); return new SimpleAuthenticationInfo(userVO.getUsername(), userVO.getPassword() ,getName()); } return null; }}
Two important ways :doGetAuthorizationInfo
: Used to control the permissions of login users , about admin
The user has made special treatment , give *:*
All permissions doGetAuthenticationInfo
: For login , Check the user's account password , Log in successfully and send the user information , With Constants.SESSION_KEY As key Deposit in session in , In this way, you can get from session To retrieve user information (PS: If it's a distributed project , You can also transfer the user information to json after , There is redis in , You can search relevant articles online by yourself :shiro Distributed storage session)
Log management
Log management uses AOP To achieve , The code is as follows :
/** * Log collection */@Slf4j@Aspect@Componentpublic class LogAop { @Autowired private LogService logService; private static final String SAVE_TPL = " user name :{0}, Modifying data , Submit parameters :{1}"; private static final String USER_LOGIN_TPL = " user :{0} Login management background ,{1}"; @AfterReturning(value = "execution(* com.mini.admin.controller.*.*save(..))", returning = "result") public void afterSaveReturn(JoinPoint joinPoint, Object result) { try { Subject subject = SecurityUtils.getSubject(); Session session = subject.getSession(); UserVO userVO = (UserVO) session.getAttribute(Constants.SESSION_KEY); LogVO logVO = new LogVO(); logVO.setUsername(userVO.getUsername()); logVO.setRemark(JSON.toJSONString(joinPoint.getArgs())); logVO.setLoginIp(session.getHost()); logVO.setGmtCreate(new Date()); String editAccountStr = MessageFormat.format(SAVE_TPL, logVO.getUsername(), logVO.getRemark()); logVO.setRemark(editAccountStr); logService.insert(logVO); } catch (Exception ex) { log.warn(" An exception occurred in log collection :{}", ex.getMessage(), ex); } } @SuppressWarnings("unchecked") @AfterReturning(value = "execution(* com.mini.admin.controller.IndexController.loginSubmit(..))", returning = "result") public void afterLoginReturn(JoinPoint joinPoint, Object result) { try { Subject subject = SecurityUtils.getSubject(); Session session = subject.getSession(); Result<String> stringResult = (Result<String>) result; Object[] methodArgs = joinPoint.getArgs(); UserVO userVO = (UserVO) methodArgs[0]; LogVO logVO = new LogVO(); logVO.setUsername(userVO.getUsername()); logVO.setRemark(JSON.toJSONString(methodArgs)); logVO.setLoginIp(session.getHost()); logVO.setGmtCreate(new Date()); String loginStatus = ""; if (stringResult.isSuccess()){ loginStatus = " success "; }else { loginStatus = " Failure , Submit parameters :"+ logVO.getRemark(); } String str = MessageFormat.format(USER_LOGIN_TPL,logVO.getUsername(),loginStatus); logVO.setRemark(str); logService.insert(logVO); } catch (Exception ex) { log.warn(" An exception occurred in log collection :{}", ex.getMessage(), ex); } }}
This is mainly for Controller Of save Relevant methods and login operations are captured , And record the submitted parameters . So who logged in , The user's account password is clearly recorded .
id | username | login_ip | gmt_create | remark |
---|---|---|---|---|
2351 | admin | 0:0:0:0:0:0:0:1 | 2022-06-30 23:57:47.0 | user :admin Login management background , Failure , Submit parameters :[{“length”:10,“password”:“14e1b600b1fd579f47433b88e8d85291”,“start”:1,“username”:“admin”}] |
You can think about , If an exception occurs when writing the log table , There is no try catch, Will the original calling method rollback the data ?
Resource management
Omit , See source code , Contact me if you don't understand , Free support
Role management
Account management
Institutional Management
The data dictionary
Attachment Management
Applet management - User management
Small program function realization
Bluetooth door opening front end
<view class='container'> <view class="flex-grow-1 flex-x-center flex-row home-class"> <label class="loginLab"> Bluetooth status :{{blueStatus}}</label> </view> <view class="flex-grow-1 flex-x-center flex-row"> <label class="loginLab"><text class="{{isOpening?'ds':'df'}}">{{doorStatusTxt}}</text></label></view> <view class="openBtnView flex-grow-1 flex-x-center flex-row {{isClick?'view2':'view1'}}" bindtap="{{isOpening?'openDoorNo':'openDoor'}}"> <!--<button class="openBtn" bindtap='openDoor' type="primary"> Open door </button> --> <text class='openBtnText'> Open the door button </text> </view></view>
blueStatus、doorStatusTxt
It's a variable- The style of the door opening button , adopt
{{isClick?'view2':'view1'}}
control , If it's pressed , Use view2 style , Otherwise use view1 style {{isOpening?'openDoorNo':'openDoor'}}
Bound to different door opening states , Executed function
Let's take a look JS Implementation part
Bluetooth door code implementation
openDoor function
openDoor: function() { var that = this; that.setData({ isOpen:false, isOpening: true, isClick: true, blueStatus: " Unconnected ", doorStatusTxt: " Opening the door " }); this.createBLEConnection(function() { console.log(" Open the door for the first time ..."); that.writeBLECharacteristicValue(); }); }
First, when opening the door, the relevant variables will be assigned , For front page display ,isOpen: Whether to open the door ,isOpening: Is the door opening ,isClick: Did you click the button ,blueStatus: The front page status is displayed as “ Unconnected ”,doorStatusTxt: Display the opening status text .
a key :
writeBLECharacteristicValue
: Send a door opening request to Bluetooth
openDoorNo function
openDoorNo: function() { console.log(" Opening the door , Please do not click again "); }
This is an empty function , This function is used to control the number of clicks , It doesn't repeat
writeBLECharacteristicValue Write Bluetooth data
writeBLECharacteristicValue() { var that = this; // Send a 0x00 Of 16 Hexadecimal data let buffer = new ArrayBuffer(16) let dataView = new DataView(buffer) let data = new Array(); if(this.data.userInfo.address) { data = this.data.userInfo.address.split(","); } console.log(data); dataView.setUint16(0, data[0]); dataView.setUint16(2, data[1]); dataView.setUint16(4, data[2]); wx.writeBLECharacteristicValue({ deviceId: this._deviceId, serviceId: this._serviceId, characteristicId: this._characteristicId, value: buffer, success: (res) => { console.log(" Write successfully ") util.sleep(1000); if(!that.data.isOpen) { that.setData({ isClick: false, isOpening: false, doorStatusTxt: " Failed to open the door " }); that.closeBLEConnection(); } }, fail: (res) => { console.log(" Write failure ") util.sleep(1000); if(!that.data.isOpen) { that.setData({ isClick: false, isOpening: false, doorStatusTxt: " Failed to open the door " }); that.closeBLEConnection(); } }, }) }
data = this.data.userInfo.address.split(",");
Here, the user's house address information obtained from the back end will be divided , write in dataView.setUint16(0, data[0]);
General owners may have multiple Suites , Need to write all their houses into Bluetooth , In this way, the owner can open multiple bluetooth access control units with the same wechat
This part is the code of Bluetooth door opening , The premise of this is that Bluetooth has been successfully connected , Let's take a look at the code implementation of other parts , I have annotated the code .
//index.js// Get application instance const app = getApp()var util = require('../../../utils/util.js');function inArray(arr, key, val) { for (let i = 0; i < arr.length; i++) { if (arr[i][key] === val) { return i; } } return -1;}// ArrayBuffer turn 16 Example progress string function ab2hex(buffer) { var hexArr = Array.prototype.map.call( new Uint8Array(buffer), function (bit) { return ('00' + bit.toString(16)).slice(-2) } ) return hexArr.join('');}// String rotation bytefunction stringToBytes(str) { var array = new Uint8Array(str.length); for (var i = 0, l = str.length; i < l; i++) { array[i] = str.charCodeAt(i); } console.log(array); return array.buffer;}Page({ data: { userInfo: null, devices: [], connected: false, chs: [], blueStatus: " Unconnected ", doorStatusTxt: " Not open the door ", isOpen: false, isOpening: false, isClick: false, intervalId: 0, isIOS: 0 }, onLoad: function () { var userInfo = wx.getStorageSync("userInfo"); var that = this; if(!userInfo){ wx.redirectTo({ url: '/pages/me/login/login', }) }else{ that.setData({userInfo: userInfo}); setTimeout(function () { that.openBluetoothAdapter(); }, 300); }; wx.getSystemInfo({ success: function(res) { if(res.platform == 'ios') { that.setData({isIOS: 1}); } }, }) }, onShow: function() { var userInfo = this.data.userInfo; var that = this; if (!userInfo) { wx.redirectTo({ url: '/pages/me/login/login', }) return; } // Judge whether the user is disabled in the background that.userIsDisable(userInfo.userId); this.setData({ doorStatusTxt: " Not open the door ", isOpen: false}); wx.onAccelerometerChange(function (res) { //console.log(res.x + " /" + res.y + " /" + res.z); if (res.x > 0.3 && res.y > 0.6) { var isOpening = that.data.isOpening; if(!isOpening) { wx.showToast({ title: ' Shake a success ', duration: 2000 }) wx.vibrateLong(); that.openDoor(); } } }); if(this.data.isIOS == 1) { var intervalId = setInterval(this.getBluetooth, 1000); this.setData({ intervalId: intervalId }); } }, onUnload: function() { var userInfo = this.data.userInfo; if(userInfo){ this.closeBLEConnection(); } }, // forward onShareAppMessage: function () { wx.showShareMenu({ withShareTicket: true }); var option = { title: ' Bluetooth access control ', path: '/pages/home/index/index', success: function (res) { } } return option; }, userIsDisable: function(userId) { var data = { userId:userId }; var url = app.globalData.gwapi + "user/getUserInfo"; util.sendPost(url,data,function(res){ if(res.code == 0){ // Account has been deactivated if(!res.data) { wx.removeStorageSync("userInfo"); wx.redirectTo({ url: '/pages/me/login/login', }) } } }); }, openDoorNo: function() { console.log(" Opening the door , Please do not click again "); }, openDoor: function() { var that = this; that.setData({ isOpen:false, isOpening: true, isClick: true, blueStatus: " Unconnected ", doorStatusTxt: " Opening the door " }); this.createBLEConnection(function() { console.log(" Open the door for the first time ..."); that.writeBLECharacteristicValue(); }); }, openBluetoothAdapter() { var that = this; wx.openBluetoothAdapter({ success: (res) => { console.log('openBluetoothAdapter success', res) that.startBluetoothDevicesDiscovery(); this.setData({ blueStatus: " Bluetooth is on " }) }, fail: (res) => { if (res.errCode === 10001) { this.setData({ blueStatus: " Bluetooth is not turned on " }) wx.onBluetoothAdapterStateChange(function (res) { console.log('onBluetoothAdapterStateChange', res) if (res.available) { that.setData({ blueStatus: " Bluetooth is on " }) } }) } } }) }, // Create a Bluetooth connection createBLEConnection(fc) { console.log(" Create a Bluetooth connection ") const deviceId = this.data.userInfo.bluetoothCode; wx.createBLEConnection({ deviceId, timeout: 2000, success: (res) => { this.setData({ blueStatus: " Connected ", }) this.getBLEDeviceServices(deviceId, fc) }, fail: (res) => { this.setData({ isOpening: false, isClick: false, blueStatus: " The connection fails ", doorStatusTxt: " Not open the door " }); } }) }, // Turn off the Bluetooth connection closeBLEConnection() { var deviceId = this.data.userInfo.bluetoothCode; console.log(" Turn off the Bluetooth connection ") wx.closeBLEConnection({ deviceId: deviceId }) this.setData({ connected: false, chs: [], canWrite: false, blueStatus: " Unconnected " }) }, getBluetooth() { var that = this; wx.getBluetoothDevices({ success: function (res) { that.setData({ devices: res.devices }); let deviceList = that.data.devices; for (var i = 0; i < deviceList.length; i++) { if (deviceList[i].advertisData != null) { // a key according to advertisData Take out mac Splicing let bf = deviceList[i].advertisData.slice(4, 10); let mac = ab2hex(bf).toUpperCase(); console.log("mac: "+mac); var deviceId = that.data.userInfo.bluetoothCode.replace(/:/g,""); console.log("deviceId: " + deviceId); if (mac == deviceId) { that.data.userInfo.bluetoothCode = deviceList[i].deviceId; that.stopBluetoothDevicesDiscovery(); } } } clearInterval(that.data.intervalId); }, fail: function (res) { }, complete: function (res) { }, }) }, // Get all services from Bluetooth devices getBLEDeviceServices(deviceId, fc) { console.log(" Get Bluetooth service ") wx.getBLEDeviceServices({ deviceId, success: (res) => { for (let i = 0; i < res.services.length; i++) { if (res.services[i].isPrimary) { this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid, fc) return } } } }) }, // Get all the eigenvalues in a service of a Bluetooth device getBLEDeviceCharacteristics(deviceId, serviceId, fc) { wx.getBLEDeviceCharacteristics({ deviceId, serviceId, success: (res) => { console.log('getBLEDeviceCharacteristics success', res.characteristics) for (let i = 0; i < 1; i++) { let item = res.characteristics[i] if (item.properties.write) { this._deviceId = deviceId this._serviceId = serviceId this._characteristicId = item.uuid console.log(serviceId); //this.writeBLECharacteristicValue() } if (item.properties.notify || item.properties.indicate) { wx.notifyBLECharacteristicValueChange({ deviceId, serviceId, characteristicId: item.uuid, state: true, success: (res) => { console.log(res.errMsg) this.onBLECharacteristicValueChange() }, fail: (res) => { console.log(res.errMsg) } }) } } // Callback fc(); }, fail(res) { console.error('getBLEDeviceCharacteristics', res) } }) }, // Listen before operation , Make sure you get the data in the first place onBLECharacteristicValueChange() { wx.onBLECharacteristicValueChange((characteristic) => { const idx = inArray(this.data.chs, 'uuid', characteristic.characteristicId) console.log(ab2hex(characteristic.value)); var data = ab2hex(characteristic.value); console.log(data); if (data = 'cc'){ this.setData({ doorStatusTxt: " Opened ", isOpen: true, isClick: false, isOpening:false}); this.closeBLEConnection(); wx.vibrateLong(); } }) }, writeBLECharacteristicValue() { var that = this; // Send a 0x00 Of 16 Hexadecimal data let buffer = new ArrayBuffer(16) let dataView = new DataView(buffer) let data = new Array(); if(this.data.userInfo.address) { data = this.data.userInfo.address.split(","); } console.log(data); dataView.setUint16(0, data[0]); dataView.setUint16(2, data[1]); dataView.setUint16(4, data[2]); wx.writeBLECharacteristicValue({ deviceId: this._deviceId, serviceId: this._serviceId, characteristicId: this._characteristicId, value: buffer, success: (res) => { console.log(" Write successfully ") util.sleep(1000); if(!that.data.isOpen) { that.setData({ isClick: false, isOpening: false, doorStatusTxt: " Failed to open the door " }); that.closeBLEConnection(); } }, fail: (res) => { console.log(" Write failure ") util.sleep(1000); if(!that.data.isOpen) { that.setData({ isClick: false, isOpening: false, doorStatusTxt: " Failed to open the door " }); that.closeBLEConnection(); } }, }) }, closeBluetoothAdapter() { wx.closeBluetoothAdapter() this._discoveryStarted = false }, // Get the status of the native Bluetooth adapter getBluetoothAdapterState() { wx.getBluetoothAdapterState({ success: (res) => { console.log('getBluetoothAdapterState', res) if (res.discovering) { this.onBluetoothDeviceFound() } else if (res.available) { this.startBluetoothDevicesDiscovery() } } }) }, // Start searching for Bluetooth startBluetoothDevicesDiscovery() { if (this._discoveryStarted) { return } this._discoveryStarted = true wx.startBluetoothDevicesDiscovery({ success: (res) => { console.log('startBluetoothDevicesDiscovery success', res) this.onBluetoothDeviceFound() }, }) }, // End Searching Bluetooth stopBluetoothDevicesDiscovery() { wx.stopBluetoothDevicesDiscovery() }, // Find a new Bluetooth event onBluetoothDeviceFound() { wx.onBluetoothDeviceFound((res) => { console.log(res.devices); }) },})
Someone might ask , Yours util What is it? ,util It's my own encapsulated request get、post A simple way to solve this problem , And the method of formatting time .
Come here , We 《 Wechat applet realizes Bluetooth door opening 》 It's all done , Let's see the complete effect . Applet source code private message access .
边栏推荐
- 新一代云原生消息队列(一)
- Flir Blackfly S工业相机:颜色校正讲解及配置与代码设置方法
- 【论文阅读|深读】 GraphSAGE:Inductive Representation Learning on Large Graphs
- [unity notes] screen coordinates to ugui coordinates
- Date processing tool class dateutils (tool class 1)
- #夏日挑战赛#数据库学霸笔记(下)~
- Robot team learning method to achieve 8.8 times human return
- 张平安:加快云上数字创新,共建产业智慧生态
- What to do when encountering slow SQL? (next)
- 投资的再思考
猜你喜欢
STM32F4---PWM输出
大咖云集|NextArch基金会云开发Meetup来啦!
Correct use of BigDecimal
Flir Blackfly S 工业相机 介绍
Draco - glTF模型压缩利器
Centros 8 installation MySQL Error: The gpg Keys listed for the "MySQL 8.0 Community Server" repository are already ins
Word wrap when flex exceeds width
centos8安装mysql报错:The GPG keys listed for the “MySQL 8.0 Community Server“ repository are already ins
阿里云易立:云原生如何破解企业降本提效难题?
postgresql之整體查詢大致過程
随机推荐
Recommended collection!! Which is the best flutter status management plug-in? Please look at the ranking list of yard farmers on the island!
老板被隔离了
Why am I warned that the 'CMAKE_ TOOLCHAIN_ FILE' variable is not used by the project?
大咖云集|NextArch基金会云开发Meetup来啦!
6 seconds to understand the book to the Kindle
Introduction to RC oscillator and crystal oscillator
Threadlocalutils (tool class IV)
RC振荡器和晶体振荡器简介
[C # notes] reading and writing of the contents of text files
3--新唐nuc980 kernel支持jffs2, Jffs2文件系统制作, 内核挂载jffs2, uboot网口设置,uboot支持tftp
Redis tool class redisutil (tool class III)
真实项目,用微信小程序开门编码实现(完结)
Zabbix 5.0:通过LLD方式自动化监控阿里云RDS
新一代云原生消息队列(一)
FLIR blackfly s industrial camera: explanation and configuration of color correction and code setting method
Twenty or thirty thousand a leaf? "Yang Mou" behind the explosion of plant consumption
[paper reading | deep reading] anrl: attributed network representation learning via deep neural networks
New generation cloud native message queue (I)
Command injection of cisp-pte
FLIR blackfly s industrial camera: auto exposure configuration and code