ReedawFoodApp/components/foodIndex/bluetooth_food.vue

508 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="weightPages">
<view class="table">
<view class="textTipe">
<image src="/static/zhong.png"></image>
<text @click="openBluetoothAdapter">{{bleTipsText}}</text>
</view>
<view class="duan" @click="handleBack" v-if="isShow&&isConnection == 2">
断开连接
</view>
</view>
<!-- -->
<view class="weight-wrap">
<!-- 蓝牙称重 -->
<view class="weight" @click="inputDialogToggle">
<text class="val">{{weight == '' ? '0.0':weight}}</text>
<text class="unit">{{unit}}</text>
</view>
</view>
<!-- -->
<view class="groupbtn">
<view class="btn danwei">
<view class="lan border-bottom">
<view class="right">
<picker mode="selector" :range="unitA" @change="changleUnits" :value="unitListIndex">
<view class="uni-input">
单位
</view>
</picker>
</view>
</view>
</view>
<view class="btn addbtn size14" @click="handlesub" v-if="btnType==2">保存</view>
<view class="btn addbtn" @click="handleAddFood" v-if="btnType==1">+</view>
<view class="btn qingling" @click="handleqingling">清零</view>
</view>
<!-- -->
<view>
<uni-popup ref="popup" type="dialog">
<uni-popup-dialog mode="input" title="重量" placeholder="请输入食物重量" @close="close"
@confirm="confirm"></uni-popup-dialog>
</uni-popup>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
let myTime
let nextCnt = 0
export default {
data() {
return {
kcal: 0,
unit: 'g',
deviceId: "",
serviceId: "",
notify: "",
write: "",
unitA: [],
inputDialog: false,
unitListIndex: 0,
}
},
props: {
weightKcal: {
type: Number,
default: 0 //当前测量食物每100g含的kcal
},
btnType: {
type: Number,
default: 1 //1添加食材2保存测量
}
},
computed: {
...mapState(["bleValue", "countFoodInfo", "isBluetoothTyle", ]),
weight() {
let weightNew = this.$ble.convertToGrams(this.bleValue.foodWeight, this.bleValue.foodUnit)
this.kcal = (Number(this.weightKcal) / 100 * weightNew).toFixed(1)
this.unit = this.bleValue.foodUnit
return this.bleValue.foodWeight
},
isConnection() {
return this.bleValue.isConnectStatus
},
isShow() {
return this.bleValue.serviceId != '' ? true : false
},
bleTipsText() {
return this.bleValue.bleTipsText
},
},
mounted() {
let that = this
uni.onBluetoothAdapterStateChange(function(res) {
that.$store.commit("changeBluetooth", res.available);
})
},
watch: {
isBluetoothTyle: function() {
let that = this
if (!that.isBluetoothTyle) {
that.handleBack()
}
},
bleValue: {
handler(newVal, oldVal) {
let that = this
if (newVal.serviceId) {
that.deviceId = newVal.deviceId
that.serviceId = newVal.serviceId
that.getBLEDeviceCharacteristics()
}
that.unitA = newVal.unitList
that.unitListIndex = newVal.unitList.findIndex(ite => ite == newVal.foodUnit)
},
deep: true,
immediate: true
},
},
methods: {
// 初始化蓝牙
openBluetoothAdapter() {
let that = this
if (that.isConnection != 1) return
that.kcal = ""
that.$store.commit('changeBluetoothValue', {
bleTipsText: "蓝牙搜索中",
isConnectStatus: 0,
deviceId: "",
serviceId: "",
foodNotify: "",
foodType: 1,
foodWrite: "",
foodWeight: 0,
foodUnit: "g",
unitList: that.$json.unitMinus,
})
that.$ble.openBluetoothAdapter()
},
/**
* 获取指定服务的特征值
*/
getBLEDeviceCharacteristics() {
let that = this
uni.getBLEDeviceCharacteristics({
deviceId: that.deviceId,
serviceId: that.serviceId,
success: res => {
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i];
if (item.uuid.indexOf('0000FFF2') != -1) {
that.write = item.uuid
} else if (item.uuid.indexOf('0000FFF1') != -1) {
that.notify = item.uuid
}
}
that.getBLECharacteristicValueChange()
},
fail: res => {
that.$store.commit("changeBluetoothValue", {
foodType: 1,
isConnectStatus: 1,
bleTipsText: "连接超时,点击重新连接",
})
console.log('获取特征值失败:', JSON.stringify(res))
}
})
},
getBLECharacteristicValueChange() {
let that = this
uni.notifyBLECharacteristicValueChange({
deviceId: that.deviceId,
serviceId: that.serviceId,
characteristicId: that.notify,
state: true,
success: () => {
that.$store.commit('changeBluetoothValue', {
deviceId: that.deviceId,
serviceId: that.serviceId,
foodNotify: that.notify,
foodWrite: that.write,
bleTipsText: "测量中,请将食物放到秤上",
isConnectStatus: 2
})
uni.onBLECharacteristicValueChange(function(res) {
const value = res.value
const dataView = new DataView(value)
const header = dataView.getUint8(0)
// MCU主动上报数据
if (header === 0xC7) {
const cmd = dataView.getUint8(2)
switch (cmd) {
case 0x02:
const statusByte = dataView.getUint8(4)
const isNegative = !!(statusByte & 0x80) // 最高位表示正负
const statusType = statusByte & 0x0F // 状态类型
// 组合24位重量值 (大端序)
const weightValue =
(dataView.getUint8(5) << 16) |
(dataView.getUint8(6) << 8) |
dataView.getUint8(7)
// 精度和单位
const unitByte = dataView.getUint8(8)
const precision = (unitByte & 0xF0) >> 4 // 高4位精度
const unitIndex = unitByte & 0x0F // 低4位单位
// 计算实际重量
let finalWeight = weightValue / Math.pow(10, precision)
if (isNegative) finalWeight = -finalWeight
that.$store.commit("changeBluetoothValue", {
foodWeight: finalWeight,
foodUnit: that.$json.units[unitIndex],
foodType: statusType
})
console.log('重量:' + finalWeight, "状态:" + statusType)
console.log('单位:' + that.$json.units[unitIndex])
break
case 0x03:
break
case 0x08:
const start0 = []
const value2 = that.$tools.ab2hex(value, "");
const start = that.$tools.parseUnitMask(value2.substring(8,
10), that.$json.units.slice(0, 7))
const start1 = that.$tools.parseUnitMask(value2.substring(10,
12), that.$json.units.slice(8, 10))
start.push.apply(start, start1)
if (start.length) {
that.$json.unitMinus.forEach(item => {
start.forEach(item2 => {
if (item == item2) {
start0.push(item)
}
})
})
}
that.$store.commit("changeBluetoothValue", {
unitList: start0.length ? start0 : that.$json
.unitMinus
})
console.log("22222222222222", start, start0)
break
}
}
})
},
fail: res => {
console.log('获取特征值失败:', JSON.stringify(res))
}
})
},
changleUnits(e) {
let that = this
let unit = that.unitA[e.detail.value]
console.log("danwei", that.unit, unit, e.detail.value)
if (that.isShow && that.unit != unit) {
that.handletoggleUnit(that.$ble.unitInstruction(unit))
}
if (that.bleValue.serviceId == '') {
that.unitListIndex = e.detail.value
that.$store.commit('changeBluetoothValue', {
foodUnit: that.unitA[e.detail.value],
})
}
},
// 下发单位
handletoggleUnit(unit) {
let that = this
let checksum = 0;
const bytes = [0xC5, 0x03, 0x05, 0x11]
bytes[4] = unit
for (let i = 0; i < bytes.length; i++) {
checksum ^= bytes[i];
}
bytes[5] = checksum
that.sendData(new Uint8Array(bytes).buffer)
},
// 清零
handleqingling() {
let that = this
let str = "C503071100D0"
let buf = new Uint8Array(str.match(/[\da-f]{2}/gi).map(function(h) {
return parseInt(h, 16)
}))
that.sendData(buf.buffer)
},
sendData(buffer) {
let that = this
uni.writeBLECharacteristicValue({
deviceId: that.deviceId,
serviceId: that.serviceId,
characteristicId: that.write,
value: buffer,
success: res => {
console.log('下发指令成功', res.errMsg)
},
fail: res => {
console.log("下发指令失败", res);
},
})
},
// 保存测量结果
handlesub() {
let that = this
console.log("测量保存", that.weight, that.unit, that.kcal)
if (Number(that.weight) > 0) {
that.$emit("handleBle", that.weight, that.unit, that.kcal)
} else {
that.$tools.msg("数据异常,请清零后重新测量!")
}
},
handleBack() {
let that = this
that.$store.commit("changeBluetoothValue", {
bleTipsText: "连接失败,点击重新连接",
unitList: that.$json.unitMinus,
isConnectStatus: 1,
foodType: 1
})
that.$ble.stopBluetoothDevicesDiscovery() //取消蓝牙搜索
that.$ble.closeBLEConnection(that.deviceId)
that.$ble.closeBluetoothAdapter()
},
// 添加食物
handleAddFood() {
uni.navigateTo({
url: "/Food/count/search?name=早餐&time=" + this.countFoodInfo.date
})
},
inputDialogToggle() {
this.$refs.popup.open()
},
// 手动输入
confirm(value) {
let that = this
that.$store.commit("changeBluetoothValue", {
foodWeight: value,
foodUnit: that.unitA[that.unitListIndex]
})
that.$refs.popup.close()
},
close() {
this.$refs.popup.close()
},
},
}
</script>
<style scoped lang="scss">
image {
width: 22px;
height: 22px;
}
.more {
padding: 6rpx 10rpx;
border-radius: 12rpx;
color: #fff;
background-color: #f0ae43;
}
.weightPages {
display: flex;
flex-wrap: wrap;
flex-direction: column;
position: relative;
background: #fff;
border-radius: 20rpx;
justify-content: space-around;
.weight-wrap {
display: flex;
justify-content: center;
align-items: center;
background: #fff;
color: #666;
font-size: 16px;
text-align: center;
height: 60px;
margin: 10px 0;
.weight,
.kcal {
display: flex;
justify-content: center;
align-items: center;
width: 70%;
padding: 30rpx 0;
border-radius: 20rpx;
background-color: #F8F8F8;
}
.weight {
.val {
font-size: 54rpx;
color: #F0AE43;
margin: 0 !important;
}
.unit {
padding: 10rpx;
margin-left: 30rpx;
font-size: 28rpx;
color: #fff;
border-radius: 8rpx;
background-color: #F0AE43;
}
}
}
.tips {
font-size: 24rpx;
text-align: center;
}
.groupbtn {
margin-top: 15px;
display: flex;
align-items: center;
justify-content: space-between;
.btn {
width: 30%;
color: $maincolor;
text-align: center;
height: 40px;
line-height: 40px;
border-radius: 10px;
border: 1px solid $maincolor;
background: #fff;
margin: 0;
box-sizing: border-box;
}
.addbtn {
width: 30%;
color: #fff;
font-size: 45px;
line-height: 38px;
background: $maincolor;
}
}
.table {
width: 100%;
font-size: 14px;
align-items: center;
padding: 5px 0;
border-radius: 5px;
display: flex;
justify-content: space-between;
.textTipe {
color: #8284f0;
display: flex;
align-items: center;
}
image {
width: 22px;
height: 22px;
margin-right: 5px;
}
}
.image {
width: 1120rpx;
height: 1120rpx;
margin: auto;
image {
width: 100%;
height: 100%;
}
}
.duan {
width: fit-content;
background: linear-gradient(-90deg, #d4f5c4, #a7d5e4 80%, );
border-radius: 5px;
text-align: center;
padding: 3px 10px;
font-size: 12px;
}
.tips {
margin-top: 30rpx;
margin-left: 30rpx;
display: flex;
color: #999;
}
}
</style>