基于STM32蓝牙水流量控制系统

一、介绍系统

本系统简单来说就是一个蓝牙水控系统,通过蓝牙控制开关水,并计算用水量和用水价格,很适用于高校的热水系统。

二、系统功能

1.系统构成

系统大致主要分为软件和硬件两大部分,硬件部分主要有单片机(STM32)、蓝牙模块(ECB02H2)、水流量传感器(YFS201C)、继电器这几部分组成;软件部分主要是android小程序和onenet云平台。

2.系统功能

功能:整个系统就是app通过手机蓝牙发送open指令,硬件接收到open指令后,打开继电器,开始供水,水流量传感器就开始采集计算用水量,并通过用水量计算出费用,并且2秒实时将瞬时流量、累计流量、费用,通过蓝牙模块发送到安卓小程序上,安卓小程序接收到数据后,通过手机网络将数据上传至onenet云平台,最后也可以通过手机app端发送close,关闭继电器。

3.系统框架图

三、硬件程序

1.水流量传感器驱动和采集程序:

.c文件

#include "YFS201C.h"

GOLBAL_FLOW golbal_flow;
int time1=0;

#define Flow_Model_4           1            //4分管定义为1;6分管定义为0
#define MODE_4_K               5.0f
#define MODE_4_PLUSE_CNT_1L		 300.0f
#define MODE_6_K               5.5f
#define MODE_6_PLUSE_CNT_1L    330.0f
#define	FLOW_FULL					     1000000


//用PD2的外部中断来获取低电平的脉冲
void Exit2_Config(void)
{
  EXTI_InitTypeDef EXTI_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
  
	//**********映射配置**************	
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource4);
  
  //Config EXTI4 line
  EXTI_ClearITPendingBit(EXTI_Line4);
  EXTI_InitStructure.EXTI_Line = EXTI_Line4;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;    //下降沿触发中断
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
  
  NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; 
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
  NVIC_Init(&NVIC_InitStructure);
	
	EXTI->IMR &= ~(EXTI_Line4);
}
  
void EXTI4_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line4) != RESET)
  {
    golbal_flow.pluse_1s++;           //下降沿采集脉冲数
  }
  EXTI_ClearITPendingBit(EXTI_Line4); //清除Line4的中断标志位
}

void Flow_Read(void)
{
	if(golbal_flow.receive_flag)
	{
		if(golbal_flow.pluse_1s > 0)
		{
      #ifdef Flow_Model_4
			/*计算公式:
				累计流量 = 对瞬时流量做积分
								 = (脉冲频率 / 300个脉冲)    //1L需要300个脉冲,脉冲频率HZ
			*/
			golbal_flow.acculat += golbal_flow.pluse_1s / MODE_4_PLUSE_CNT_1L;   //单位L
				
			/*计算公式:
						瞬时流量 = (脉冲频率 / 300个脉冲) * 60s 
										 = 脉冲频率 / 5.0(流量系K)
			*/
			golbal_flow.instant = golbal_flow.pluse_1s / MODE_4_K;  //单位(L/min)
      
      #else
      	/*计算公式:
				累计流量 = 对瞬时流量做积分
								 = (脉冲频率 / 330个脉冲)    //1L需要330个脉冲,脉冲频率HZ
			*/
			golbal_flow.acculat += golbal_flow.pluse_1s / MODE_6_PLUSE_CNT_1L;   //单位L
				
			/*计算公式:
						瞬时流量 = ((脉冲频率 + 3) / 330个脉冲) * 60s 
										 = (脉冲频率 + 3) / 5.5(流量系K)
			*/
			golbal_flow.instant = (golbal_flow.pluse_1s + 3) / MODE_6_K;  //单位(L/min)
      #endif
      
      if(golbal_flow.acculat >= FLOW_FULL)
			{
				golbal_flow.acculat = 0;
			}
		}
		else
		{
			golbal_flow.instant  = 0;
		}				
      
		//1升=0.001m^3    3.5¥/m^3
		golbal_flow.money=(golbal_flow.acculat*0.001)*3.5; 
		
		printf("瞬间流量:%.2f(L/min) 累计流量:%.2f(L) money:%.2f\n",golbal_flow.instant,golbal_flow.acculat,golbal_flow.money);
				
		golbal_flow.receive_flag = 0;     			 //接收完成标志位清零
	
    golbal_flow.pluse_1s = 0;
		
		
	}
}

void TIM3_Int_Init(u16 arr,u16 psc)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //①时钟 TIM3 使能
	
	//定时器 TIM3 初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化 TIM3
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //允许更新中断
	
	//中断优先级 NVIC 设置
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级 0 级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级 3 级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
	NVIC_Init(&NVIC_InitStructure); //④初始化 NVIC 寄存器
	TIM_Cmd(TIM3, ENABLE); //⑤使能 TIM3
	
	TIM3->CR1 &= ~(0x01);
}


//定时器 3 中断服务程序
void TIM3_IRQHandler(void) //TIM3 中断
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查 TIM3 更新中断发生与否
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除 TIM3 更新中断标志
		golbal_flow.receive_flag = 1;
		time1++;
	}
}

.h文件
#ifndef _YFS201C_H
#define _YFS201C_H

#include "stm32f10x.h"
#include "usart.h"

typedef struct
{
	uint8_t receive_flag;   //多久读取标志位
	uint16_t pluse_1s;   //脉冲频率
	
	float instant;   //瞬时流量
	float acculat;   //累计流量
	float money;
}GOLBAL_FLOW;

extern GOLBAL_FLOW  golbal_flow;

void Exit2_Config(void);
void Flow_Read(void);
void TIM3_Int_Init(u16 arr,u16 psc);

#endif
2.识别手机app端发送的消息指令
u8 rxbuff[30] = {0};
int flag=0,count_open=0,count_close=0;
int flag1=0;

void USART3_IRQHandler(void)
{	
	u8 res;
	static u8 index = 0;
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
	{
		if(index>=29)  //发生溢出
		{
			index=0;
			memset(rxbuff,0,30);
		}
		
		res = USART_ReceiveData(USART3);
		rxbuff[index] = res;
		index++;
  }
	
	if(strstr((char *)rxbuff,"open"))
	{
		if(flag1==0)
		{
			flag1=1;
			if(flag!=1) flag=1;
			count_open++;
		}
		memset(rxbuff,0,30);
		index=0;	
	}
		
	else if(strstr((char *)rxbuff,"close"))
	{
		if(flag1==1)
		{
			flag1=0;
			if(flag!=0) flag=0;
			count_close++;
		}
		memset(rxbuff,0,30);
		index=0;
	}	


  
	USART_ClearFlag(USART3,USART_FLAG_TC);
}
3.控制开和关的逻辑程序
if(flag)
		{
			TIM3->CR1 |= 0x01;
			EXTI->IMR |= EXTI_Line4;
			relay=1;
			
			
			if(count_open==2 && count_close==1)
			{
				count_close=0;
				count_open=1;
				golbal_flow.instant=golbal_flow.acculat=golbal_flow.money=0;	
			}
      if(count_open>2) count_open=0;		
			
		}
		else
		{
			if(count_close>1) count_close=0;
			TIM3->CR1 &= ~(0x01);
			EXTI->IMR &= ~(EXTI_Line4);
			relay=0;
		}
		
		
		//bulebooth send data
		if(time1>=2)
		{
			time1=0;
			UsartPrintf3("ins:%.1f sum:%.1f money:%.2f\r\n",golbal_flow.instant,golbal_flow.acculat,golbal_flow.money);
			delay_ms(3000);
		}

以上就是硬件实现的程序,水流量传感器信号端输出的就是脉冲,所以就用的外部中断来获取这个信号量就很合适。 

四、软件程序

1.蓝牙库程序
package cn.eciot.ble_demo_java;

import android.Manifest;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.os.Build;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

import java.util.ArrayList;
import java.util.List;

interface ECBluetoothAdapterStateChangeCallback {
    void callback(boolean ok, int errCode, String errMsg);
}

interface ECBluetoothDeviceFoundCallback {
    void callback(String id, String name, String mac, int rssi);
}

interface ECBLEConnectionStateChangeCallback {
    void callback(boolean ok, int errCode, String errMsg);
}

interface ECBLECharacteristicValueChangeCallback {
    void callback(String str, String strHex);
}

public class ECBLE {
    private static BluetoothAdapter bluetoothAdapter = null;
    private static ECBluetoothAdapterStateChangeCallback ecBluetoothAdapterStateChangeCallback = (boolean ok, int errCode, String errMsg) -> {
    };

    static void onBluetoothAdapterStateChange(ECBluetoothAdapterStateChangeCallback cb) {
        ecBluetoothAdapterStateChangeCallback = cb;
    }

    static void openBluetoothAdapter(Context ctx) {
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter == null) {
            ecBluetoothAdapterStateChangeCallback.callback(false, 10000, "此设备不支持蓝牙");
            return;
        }
        if (!bluetoothAdapter.isEnabled()) {
            ecBluetoothAdapterStateChangeCallback.callback(false, 10001, "请打开设备蓝牙开关");
            return;
        }

        LocationManager locationManager = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);
        boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        if (!(gps || network)) {
            ecBluetoothAdapterStateChangeCallback.callback(false, 10002, "请打开设备定位开关");
            return;
        }

        ecBluetoothAdapterStateChangeCallback.callback(true, 0, "");

        if (bluetoothGatt != null) {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
                if (ActivityCompat.checkSelfPermission(ctx, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                    return;
                }
            }
            bluetoothGatt.close();
        }
    }

    //--------------------------------------------------------------------------------------------
    private static final List<BluetoothDevice> deviceList = new ArrayList<>();
    private static boolean scanFlag = false;
    private static ECBluetoothDeviceFoundCallback ecBluetoothDeviceFoundCallback = (String id, String name, String mac, int rssi) -> {
    };

    static void onBluetoothDeviceFound(ECBluetoothDeviceFoundCallback cb) {
        ecBluetoothDeviceFoundCallback = cb;
    }

    private static final BluetoothAdapter.LeScanCallback leScanCallback = (BluetoothDevice bluetoothDevice, int rssi, byte[] bytes) -> {
        try {
//        Log.e("bytes",bytesToHexString(bytes));
//        String name = getBluetoothName(bytes);
            @SuppressLint("MissingPermission")
            String name = bluetoothDevice.getName();
            if (name == null || name.equals("")) return;

            String mac = bluetoothDevice.getAddress();
            if (mac == null || mac.equals("")) return;
            mac = mac.replace(":", "");

//        Log.e("bleDiscovery", name + "|" + mac +"|"+ rssi);

            boolean isExist = false;
            for (BluetoothDevice tempDevice : deviceList) {
                if (tempDevice.getAddress().replace(":", "").equals(mac)) {
                    isExist = true;
                    break;
                }
            }
            if (!isExist) {
                deviceList.add(bluetoothDevice);
            }
            ecBluetoothDeviceFoundCallback.callback(mac, name, mac, rssi);
        }catch (Throwable e){
            Log.e("LeScanCallback","Throwable");
        }
    };

    static void startBluetoothDevicesDiscovery(Context ctx) {
        if (!scanFlag) {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
                if (ActivityCompat.checkSelfPermission(ctx, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
                    return;
                }
            }
            if (bluetoothAdapter != null) {
                bluetoothAdapter.startLeScan(leScanCallback);
                scanFlag = true;
            }
        }
    }

    static void stopBluetoothDevicesDiscovery(Context ctx) {
        if (scanFlag) {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
                if (ActivityCompat.checkSelfPermission(ctx, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
                    return;
                }
            }
            if (bluetoothAdapter != null) {
                bluetoothAdapter.stopLeScan(leScanCallback);
                scanFlag = false;
            }
        }
    }

    //--------------------------------------------------------------------------------------------
    private static BluetoothGatt bluetoothGatt = null;
    private static boolean connectFlag = false;
    private static int reconnectTime = 0;
    private static ECBLEConnectionStateChangeCallback ecBLEConnectionStateChangeCallback = (boolean ok, int errCode, String errMsg) -> {
    };

    static void onBLEConnectionStateChange(ECBLEConnectionStateChangeCallback cb) {
        ecBLEConnectionStateChangeCallback = cb;
    }

    private static ECBLEConnectionStateChangeCallback connectCallback = (boolean ok, int errCode, String errMsg) -> {
    };
    private static ECBLECharacteristicValueChangeCallback ecBLECharacteristicValueChangeCallback = (String str, String hexStr) -> {
    };

    static void onBLECharacteristicValueChange(ECBLECharacteristicValueChangeCallback cb) {
        ecBLECharacteristicValueChangeCallback = cb;
    }

    private static final String ecCharacteristicWriteUUID = "0000fff2-0000-1000-8000-00805f9b34fb";
    private static final String ecCharacteristicNotifyUUID = "0000fff1-0000-1000-8000-00805f9b34fb";
    private static BluetoothGattCharacteristic ecCharacteristicWrite;

    private static final BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
        @SuppressLint("MissingPermission")
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            Log.e("onConnectionStateChange", "status=" + status + "|" + "newState=" + newState);
            if (status != BluetoothGatt.GATT_SUCCESS) {
                gatt.close();
                if(connectFlag){
                    ecBLEConnectionStateChangeCallback.callback(false,10000,"onConnectionStateChange:" + status + "|" + newState);
                }else{
                    connectCallback.callback(false,10000,"onConnectionStateChange:" + status + "|" + newState);
                }
                connectFlag = false;
                return;
            }
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                gatt.discoverServices();
                connectCallback.callback(true,0,"");
                ecBLEConnectionStateChangeCallback.callback(true,0,"");
                connectFlag = true;
                return;
            }
            if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                gatt.close();
                if(connectFlag){
                    ecBLEConnectionStateChangeCallback.callback(false, 0, "");
                }else {
                    connectCallback.callback(false, 0, "");
                }
                connectFlag = false;
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            bluetoothGatt = gatt;
            List<BluetoothGattService> bluetoothGattServices = bluetoothGatt.getServices();
            for (BluetoothGattService service : bluetoothGattServices) {
                Log.e("ble-service", "UUID=" + service.getUuid().toString());
                List<BluetoothGattCharacteristic> listGattCharacteristic = service.getCharacteristics();
                for (BluetoothGattCharacteristic characteristic : listGattCharacteristic) {
                    Log.e("ble-char", "UUID=:" + characteristic.getUuid().toString());
                    //notify
//                    if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
                    if(characteristic.getUuid().toString().equals(ecCharacteristicNotifyUUID)){
                        notifyBLECharacteristicValueChange(characteristic);
                    }
                    //write
                    if (characteristic.getUuid().toString().equals(ecCharacteristicWriteUUID)) {
                        ecCharacteristicWrite = characteristic;
                    }
                }
            }
            new Thread(()->{
                try {
                    Thread.sleep(300);
                    setMtu();
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }).start();
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            byte[] bytes = characteristic.getValue();
            if (bytes != null) {
                String str = new String(bytes);
                String strHex = bytesToHexString(bytes);
                Log.e("ble-receive", "读取成功[string]:" + str);
                Log.e("ble-receive", "读取成功[hex]:" + strHex);
                ecBLECharacteristicValueChangeCallback.callback(str, strHex);
            }
        }

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);
            if (BluetoothGatt.GATT_SUCCESS == status) {
                Log.e("BLEService", "onMtuChanged success MTU = " + mtu);
            } else {
                Log.e("BLEService", "onMtuChanged fail ");
            }
        }
    };

    @SuppressLint("MissingPermission")
    private static void notifyBLECharacteristicValueChange(BluetoothGattCharacteristic characteristic) {
        boolean res = bluetoothGatt.setCharacteristicNotification(characteristic, true);
        if (!res) {
            return;
        }
        for (BluetoothGattDescriptor dp : characteristic.getDescriptors()) {
            dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            bluetoothGatt.writeDescriptor(dp);
        }
    }

    @SuppressLint("MissingPermission")
    private static void setMtu() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            bluetoothGatt.requestMtu(247);
        }
    }

    @SuppressLint("MissingPermission")
    static void closeBLEConnection() {
        if (bluetoothGatt != null) {
            bluetoothGatt.disconnect();
        }
        connectFlag = false;
    }

    private static void _createBLEConnection(Context ctx, String id) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S){
            if (ActivityCompat.checkSelfPermission(ctx, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                connectCallback.callback(false,10001,"permission error");
                return;
            }
        }
        if (bluetoothGatt != null) {
            bluetoothGatt.close();
        }
        for (BluetoothDevice tempDevice : deviceList) {
            if (tempDevice.getAddress().replace(":", "").equals(id)) {
                bluetoothGatt = tempDevice.connectGatt(ctx, false, bluetoothGattCallback);
                return;
            }
        }
        connectCallback.callback(false, 10002, "id error");
    }

    static void createBLEConnection(Context ctx, String id) {
        reconnectTime = 0;
        connectCallback = (boolean ok, int errCode, String errMsg) -> {
            Log.e("connectCallback", ok + "|"+ errCode + "|"+ errMsg);
            if(!ok){
                reconnectTime = reconnectTime + 1;
                if(reconnectTime>4){
                    reconnectTime = 0;
                    ecBLEConnectionStateChangeCallback.callback(false, errCode, errMsg);
                }else{
                    new Thread(()->{
                        try {
                            Thread.sleep(300);
                            _createBLEConnection(ctx,id);
                        } catch (Throwable e) {
                            e.printStackTrace();
                        }
                    }).start();
                }
            }
        };
        _createBLEConnection(ctx,id);
    }

    @SuppressLint("MissingPermission")
    static void writeBLECharacteristicValue(String data, boolean isHex) {
        byte[] byteArray = isHex ? hexStrToBytes(data) : data.getBytes();
        ecCharacteristicWrite.setValue(byteArray);
        //设置回复形式
        ecCharacteristicWrite.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
        //开始写数据
        bluetoothGatt.writeCharacteristic(ecCharacteristicWrite);
    }

    //--------------------------------------------------------------------------------------------

    @NonNull
    private static String bytesToHexString(byte[] bytes){
        if (bytes == null) return "";
        StringBuilder str = new StringBuilder();
        for (byte b : bytes) {
            str.append(String.format("%02X", b));
        }
        return str.toString();
    }
    @NonNull
    private static byte[] hexStrToBytes(@NonNull String hexString){
        int len = hexString.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i+1), 16));
        }
        return data;
    }
    @NonNull
    private static String getBluetoothName(byte[] bytes){
        for(int i=0;i<62;i++){
            if(i>=bytes.length) return "";
            int tempLen = bytes[i];
            int tempType = bytes[i+1];
            if((tempLen==0)||(tempLen>30)){
                return "";
            }
            if((tempType == 9)||(tempType == 8)){
                byte[] nameBytes = new byte[tempLen-1];
                System.arraycopy(bytes,i+2,nameBytes,0,tempLen-1);
                return new String(nameBytes);
            }
            i+=tempLen;
        }
        return "";
    }
}
2.蓝牙连接程序
void uiInit(){
        SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.swipe_layout);
        swipeRefreshLayout.setColorSchemeColors(0x01a4ef);
        swipeRefreshLayout.setOnRefreshListener(()->{
            deviceListData.clear();
            deviceListDataShow.clear();
            listViewAdapter.notifyDataSetChanged();
            new Handler().postDelayed(()->{
                swipeRefreshLayout.setRefreshing(false);
                //权限
                permissionsInit();
            },1000);
        });

        ListView listView = findViewById(R.id.list_view);
        listViewAdapter = new Adapter(this, R.layout.list_item, deviceListDataShow);
        listView.setAdapter(listViewAdapter);
        listView.setOnItemClickListener((AdapterView<?> adapterView, View view, int i, long l)->{
            showConnectDialog();
            DeviceInfo deviceInfo = (DeviceInfo)listView.getItemAtPosition(i);
            ECBLE.onBLEConnectionStateChange((boolean ok, int errCode, String errMsg)-> runOnUiThread(()->{
                hideConnectDialog();
                if (ok) {
//                ECBLE.stopBluetoothDevicesDiscovery(this);
                    startActivities(new Intent[]{new Intent().setClass(this, DeviceActivity.class)});
                } else {
                    showToast("蓝牙连接失败,errCode="+errCode+",errMsg="+errMsg);
                    showAlert("提示","蓝牙连接失败,errCode="+errCode+",errMsg="+errMsg,()->{});
                }
            }));
            ECBLE.createBLEConnection(this,deviceInfo.id);
        });
        listRefresh();
    }
3.接收硬件传输的数据
ECBLE.onBLECharacteristicValueChange((String str,String strHex)-> runOnUiThread(()->{
            //获取当前时间,并格式化为字符串,用于显示在接收的数据前面,以标记接收时间
            @SuppressLint("SimpleDateFormat") String timeStr = new SimpleDateFormat("[HH:mm:ss,SSS]: ").format(new Date(System.currentTimeMillis()));
            String nowStr = receiveDataTextView.getText().toString();

            //将数据传递到解析函数
            Data_parse(str);


            //if()hex显示-----else()字符串显示
            if (hexRevCheckBox.isChecked()) {
                receiveDataTextView.setText(nowStr + timeStr + strHex.replaceAll("(.{2})","$1 ") + "\r\n");
            } else {
                receiveDataTextView.setText(nowStr + timeStr + str + "\r\n");
            }
            if (scrollCheckBox.isChecked()) {
                scrollView.post(()-> scrollView.fullScroll(ScrollView.FOCUS_DOWN));
            }
        }));
4.接收到数据解析程序
void Data_parse(String str_data)
    {
        // 初始化三个字符串变量
        double ins = 0.0;
        double sum = 0.0;
        double money = 0.0;

        // 切割字符串,以空格为分隔符
        String[] dataParts = str_data.split("\\s+");

        // 遍历切割得到的部分,提取数值部分
        for (String part : dataParts) {
            if (part.startsWith("ins:")) {
                String valueString = part.substring(4); // 从"ins:"后开始提取
                ins = Double.parseDouble(valueString);
            } else if (part.startsWith("sum:")) {
                String valueString = part.substring(4);
                sum = Double.parseDouble(valueString);
            } else if (part.startsWith("money:")) {
                String valueString = part.substring(6);
                money = Double.parseDouble(valueString);
            }
        }

        //传递提取出来的值
        post_data(ins,sum,money);
    }
5.数据上云程序
void post_data(double ins, double sum, double money)
    {
        new Thread(() -> {
            String url = "http://api.heclouds.com/devices/1109836136/datapoints";
            OkHttpClient okHttpClient = new OkHttpClient();

            // 构建要发送的三个消息
            String messages = "{\"datastreams\":[";
            messages += "{\"id\":\"ins\",\"datapoints\":[{\"value\":" + ins + "}]},";
            messages += "{\"id\":\"sum\",\"datapoints\":[{\"value\":" + sum + "}]},";
            messages += "{\"id\":\"money\",\"datapoints\":[{\"value\":" + money + "}]}";
            messages += "]}";

            RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), messages);

            Request request = new Request.Builder()
                    .url(url)
                    .addHeader("api-key", "wOzqMSmKBkBHXICV2P0Ud565Uno=")
                    .addHeader("Content-Type", "application/json")
                    .post(requestBody)
                    .build();

            Call call = okHttpClient.newCall(request);

            try {
                Response response = call.execute();
                if (response.code() == 200) {
                    String string = response.body().string();
                    Log.e("应答", string);
                } else {
                    Log.e("错误", "请求失败,响应码:" + response.code());
                }
            } catch (IOException e) {
                e.printStackTrace();
                Log.e("异常", "请求异常:" + e.getMessage());
            }

        }).start();
    }

五、总结

在此过程中也遇到过很多问题,其中有个问题是运行模拟机的时候正常运行,但是将APK安装在手机上,也就是运行真机的时候就会出现闪退的情况,遇到这种情况,最好的解决办法就是用根数据线连接到电脑,进行在线仿真调试,这样就能够对症下药。

给大家展示一下效果图吧!

下面是两个不同的界面,第一幅是滚动显示接收的数据,第二幅是文本显示数据。

手机端接收到一组数据,就会往云端发送一组数据。

  • 12
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值