店滴开发者手册店滴开发者手册
首页
指南
插件
接口
智能设备
element后台
SDK
首页
指南
插件
接口
智能设备
element后台
SDK
  • SDK

    • 指南
    • Uni-app SDK
    • Uni-app SDK
    • 安装与配置
    • 主 SDK 接口文档
    • 快速开始
    • WebSocket 类详细文档
    • PHP SDK文档
    • 物联网PHP SDK使用指南

Uni-app SDK

概述

店滴物联网云平台的 uni-app JavaScript SDK 是一套用于在 uni-app 项目中快速集成物联网功能的工具包。SDK 包含了 HTTP 请求、WebSocket 通信、设备控制等核心功能,帮助开发者快速构建物联网应用。

功能特性

  • HTTP 请求封装: 统一的 API 调用接口,支持拦截器、错误处理等功能
  • WebSocket 通信: 基于 WebSocket 的实时双向通信,支持设备控制和状态监听
  • 设备管理: 提供设备数据获取、控制指令发送等功能
  • 权限管理: 支持用户认证、权限验证等功能
  • 通用工具: 包含常用工具函数和常量定义

安装与配置

1. 引入 SDK

在项目的入口文件 main.js 中引入并配置 SDK:

import ddiot from '@/uni_modules/ddiot-ui/js_sdk/index.js'
import diandi from './config.js'

// 在 createApp 函数中使用
export function createApp() {
  const app = createSSRApp(App)
  const pinia = createPinia()
  app.use(pinia)
  
  // 全局挂载
  app.config.globalProperties.$wxapp_id = diandi.wxapp_id
  app.config.globalProperties.$ddiot = ddiot

  // 初始化 ddiot 插件
  app.use(ddiot, {
    websocketConf: {
      url: "wss://iot.ddicms.com:9502/addons",      // WebSocket 服务器地址
      heartRateType: 'heart',                       // 心跳类型
      authUrl: 'wss://iot.ddicms.com:9502/auth',   // 认证服务器地址
      heartRate: 20000,                            // 心跳间隔(毫秒)
      username: 'blocc',                           // 用户名
      password: '12345678',                        // 密码
      app_secret: 'c1WlCFNGJEM2PYXmifQHLrSwnkpvKuDs', // 应用密钥
      app_id: 'wPKnajOJMNX0SD5b',                 // 应用ID
    },
    http: {
      successCode: 200,
      apiConfig: {
        bloc_id: diandi.bloc_id,
        store_id: diandi.store_id,
        baseUrl: diandi.baseUrl,
        siteUrl: diandi.siteUrl,
        uploadImgUrl: diandi.baseUrl + '/upload/images',
        imgBaseUrl: diandi.siteUrl + '/attachment/',
        // ... 其他配置
      }
    }
  })

  return {
    app
  }
}

2. WebSocket 配置参数说明

参数类型必填说明
urlString是WebSocket 服务器地址
authUrlString是认证服务器地址
heartRateTypeString是心跳消息类型
heartRateNumber是心跳间隔时间(毫秒)
app_idString是应用标识符
app_secretString是应用密钥

WebSocket 使用指南

1. 初始化 WebSocket

SDK 提供了 createSocket 方法来创建 WebSocket 连接:

// 在页面或组件中使用
import { getCurrentInstance } from 'vue'

const { proxy } = getCurrentInstance()
const $ddiot = proxy.$ddiot

// 创建 WebSocket 连接
const initWebSocket = async () => {
  if ($ddiot) {
    try {
      const res = await $ddiot.createSocket('addons')
      console.log('WebSocket 创建结果:', res)
      
      if (res && $ddiot.websocket) {
        const websocket = $ddiot.websocket
        
        // 监听全局消息
        websocket.on('*', (message) => {
          console.log('全局消息监听', message)
        })
        
        // 监听临时密钥响应
        websocket.on('temp_secret_res', (message) => {
          console.log('temp_secret_res', message)
          if (message.code === 200) {
            uni.setStorageSync('app_secret', message.data.temp_secret)
          }
        })
        
        // 获取临时密钥
        websocket.emit("temp-secret", {
          'app_id': $ddiot.appId,
        }, 'auth', 'addons', 'temp-secret')
      }
    } catch (error) {
      console.error('WebSocket 初始化失败:', error)
    }
  }
}

2. WebSocket 消息监听

SDK 支持多种消息类型的监听:

// 监听临时密钥过期
websocket.on('app_secret_error', (message) => {
  console.log('app_secret_error', message)
  websocket.emit("temp-secret", {
    'app_id': $ddiot.appId,
  }, 'auth', 'addons', 'temp-secret')
})

// 监听命令响应
websocket.on('command_res', (message) => {
  console.log('command_res', message)
  if (message.code === 200) {
    uni.showLoading({
      title: message.message
    })
    setTimeout(() => {
      uni.hideLoading()
    }, 1000)
  }
})

// 监听心跳响应
websocket.on('heart_res', (message) => {
  console.log('heart_res', message)
})

// 监听操作错误
websocket.on('operation_error', (message) => {
  console.log('operation_error', message)
})

// 监听操作成功
websocket.on('operation_success', (message) => {
  console.log('operation_success', message)
  uni.showToast({
    title: '操作成功',
    duration: 1500,
    icon: 'none'
  })
})

3. 发送设备控制命令

通过 WebSocket 发送设备控制指令:

// 发送设备控制命令
const sendControlCommand = (func) => {
  if ($ddiot.websocket && $ddiot.websocket._connectioned) {
    try {
      $ddiot.websocket.emit("operation", {
        "device_id": Number(func.device_id),
        "id": func.instruction_id,
        "imei": func.device_mac,
      }, 'yrddtu', 'dtu', 'command')
    } catch (error) {
      console.error('发送命令失败:', error)
    }
  } else {
    console.log('WebSocket 连接未初始化')
  }
}

实际应用示例

设备数据展示页面

参考 allData.vue 页面的实际应用:

<template>
  <view class="page">
    <!-- Tab 切换 -->
    <scroll-view class="detail-tab" :show-scrollbar="false" id="tab-wrap" scroll-x :scroll-left="scrollLeft">
      <view v-for="(item, index) in funcList" :key="item.id" :id="'tab-' + index" class="tab-item"
        :class="{ active: current === index }" @click="changeTab(index)">
        {{ item.title }}
      </view>
    </scroll-view>

    <!-- Swiper 内容 -->
    <swiper class="detail-swiper" :current="current" @change="onSwiperChange" :duration="300">
      <swiper-item v-for="(goods, gIndex) in funcList" :key="goods.id">
        <view class="swiper-list">
          <view class="tool-item" v-for="(err, eIndex) in goods.property" :key="err.id">
            <view class="label">
              {{ err.label}}
            </view>
            <view class="data-value">
              {{ err.value }}{{ err.unit ? ' (' + err.unit + ')' : '' }}
            </view>
          </view>
        </view>
      </swiper-item>
    </swiper>
  </view>
  
  <!-- 浮动操作按钮 -->
  <view class="floating-action-btn" @click="openSetting">
    <uni-icons type="gear" size="34" color="#567feb"></uni-icons>
  </view>
  
  <!-- 设置弹窗 -->
  <uni-popup ref="popup" type="top" :safe-area="false">
    <view class="setting-popup">
      <view class="close" @click="closeSetting">
        <uni-icons type="clear" size="30" color="#9e9e9e"></uni-icons>
      </view>
      <view class="title">{{ funcList[current]?.title }}操作</view>
      <view class="list">
        <view class="list-item" v-for="(func, gIndex) in funcList[current]?.function" :key="func.id"
          @click="handleOperationClick(func)">
          <view class="label">
            {{ func.label }}
          </view>
          <view class="data-value">
            {{ func.value }}{{ func.unit ? ' (' + func.unit + ')' : '' }}
          </view>
        </view>
      </view>
    </view>
  </uni-popup>
</template>

<script setup>
import {
  onShow,
  onLoad
} from '@dcloudio/uni-app'
import {
  ref,
  nextTick,
  getCurrentInstance
} from 'vue'

const {
  proxy
} = getCurrentInstance()
const $ddiot = proxy.$ddiot
const deviceMac = ref('')

/* 数据 */
const funcList = ref([])
const current = ref(0)
const scrollLeft = ref(0)
const websocket = ref(null)
const isConnected = ref(false)

/* popup */
const popup = ref(null)

// 初始化 WebSocket
const initWebSocket = async () => {
  console.log('开始初始化 WebSocket')
  if ($ddiot) {
    try {
      const res = await $ddiot.createSocket('addons')
      console.log('WebSocket 创建结果:', res)
      
      if (res && $ddiot.websocket) {
        websocket.value = $ddiot.websocket
        isConnected.value = true
        
        // 全局消息监听
        websocket.value.on('*', (message) => {
          console.log('全局消息监听message', message)
        })
        
        // 监听临时秘钥响应
        websocket.value.on('temp_secret_res', (message) => {
          console.log('temp_secret_res', message)
          if (message.code === 200) {
            uni.setStorageSync('app_secret', message.data.temp_secret)
          }
        })

        // 监听临时秘钥过期,过期了就重新获取
        websocket.value.on('app_secret_error', (message) => {
          console.log('app_secret_error', message)
          websocket.value.emit("temp-secret", {
            'app_id': $ddiot.appId,
          }, 'auth', 'addons', 'temp-secret')
        })

        // 监听命令响应
        websocket.value.on('command_res', (message) => {
          console.log('command_res', message)
          if (message.code === 200) {
            uni.showLoading({
              title: message.message
            })
            setTimeout(() => {
              uni.hideLoading()
            }, 1000)
          }
        })
        
        // 监听心跳响应
        websocket.value.on('heart_res', (message) => {
          console.log('heart_res', message)
        })

        // 监听操作错误
        websocket.value.on('operation_error', (message) => {
          console.log('operation_error', message)
        })

        // 监听操作成功
        websocket.value.on('operation_success', (message) => {
          console.log('operation_success', message)
          // 删除缓存池该事件消息
          if (websocket.value.removeBufferByEvent) {
            websocket.value.removeBufferByEvent(message.event)
          }
        })

        // 获取临时秘钥
        websocket.value.emit("temp-secret", {
          'app_id': $ddiot.appId,
        }, 'auth', 'addons', 'temp-secret')
      }
    } catch (error) {
      console.error('WebSocket 初始化失败:', error)
    }
  }
}

/* 打开弹窗 */
const openSetting = (err) => {
  popup.value?.open()
}
const closeSetting = () => {
  popup.value?.close()
}

/* tab 切换 */
const changeTab = (index) => {
  setCurrent(index)
}

/* swiper 切换 */
const onSwiperChange = (e) => {
  setCurrent(e.detail.current)
}

const handleOperationClick = (func) => {
  console.log('WebSocket 实例:', websocket.value)
  console.log('WebSocket 连接状态:', isConnected.value)
  
  // 检查 WebSocket 连接是否存在
  if (websocket.value && isConnected.value) {
    // 发送设备控制命令示例
    try {
      websocket.value.emit("operation", {
        "device_id": Number(func.device_id),
        "id": func.instruction_id,
        "imei": func.device_mac,
      }, 'yrddtu', 'dtu', 'command')
    } catch (error) {
      console.error('发送命令失败:', error)
    }
  } else {
    console.log('WebSocket 连接未初始化')
    // 尝试重新连接
    initWebSocket()
  }
}

/* 设置当前项 + tab 自动居中 */
const setCurrent = (index) => {
  current.value = index
  scrollToTab(index)
}

// 获取设备组数据
const getDeviceGroupData = (device_mac) => {
  $ddiot.request('/device/deviceGroup', 'POST', {
    device_mac
  }, true, {
    scene: 'iot'
  }).then(res => {
    funcList.value = res.data.child_device
    nextTick(() => {
      scrollToTab(0)
    })
  })
}

onLoad((options) => {
  deviceMac.value = options.mac || ''
  getDeviceGroupData(options.mac)
  // 初始化 WebSocket 连接
  initWebSocket()
})
</script>

WebSocket 类详解

Socket 类构造函数

constructor(option = {}, route = 'addons') {
  this._url = route === 'addons' ? option.url : option.authUrl;
  this._reconnection = option.reconnection || true;        // 是否自动重连
  this._buffer = option.buffer || true;                   // 是否建立缓存池
  this._heart_rate = option.heartRate > 0 ? option.heartRate : 60000;  // 心跳间隔
  this._project_id = option.project_id;
  this._app_id = option.app_id;
  this._app_secret = option.app_secret;
  this._device_id = option.device_id;
  this.init();
}

主要方法

1. on(event, handler, single = false)

注册事件监听器

// 监听特定事件
websocket.on('command_res', (message) => {
  console.log('收到命令响应:', message)
})

// 监听所有消息
websocket.on('*', (message) => {
  console.log('收到所有消息:', message)
})

2. emit(event, param = {}, addons = '', controller = '', action = '')

发送消息到服务器

// 发送设备控制命令
websocket.emit("operation", {
  "device_id": 123,
  "id": 456,
  "imei": "device_mac_address",
}, 'yrddtu', 'dtu', 'command')

3. close()

关闭 WebSocket 连接

websocket.close()

4. getState()

获取连接状态

// 返回值:0-连接中,1-连接成功,2-重连中,3-失败
const state = await websocket.getState()

缓存池机制

SDK 提供了缓存池机制,确保在网络不稳定时消息不会丢失:

// 添加到缓存池
await websocket.addBuffer(data)

// 根据事件删除缓存
await websocket.removeBufferByEvent(event)

// 清空所有缓存
await websocket.removeBufferAll()

// 获取缓存
const buffer = await websocket.getBuffer(event)

错误处理

SDK 提供了完善的错误处理机制:

// 监听连接错误
websocket.on('error', (err) => {
  console.error('WebSocket 连接错误:', err)
})

// 监听重连错误
websocket.on('reconnectionerror', (err) => {
  console.error('WebSocket 重连错误:', err)
})

最佳实践

  1. 连接管理: 在页面加载时初始化 WebSocket,在页面卸载时正确关闭连接
  2. 状态检查: 发送消息前检查连接状态
  3. 错误处理: 始终包含适当的错误处理逻辑
  4. 资源清理: 及时移除事件监听器,避免内存泄漏
  5. 重连机制: 利用 SDK 内置的重连机制,无需手动实现

注意事项

  • 确保在发送消息前 WebSocket 已成功连接
  • 正确处理临时密钥过期的情况
  • 合理设置心跳间隔,避免频繁连接
  • 注意网络环境变化对 WebSocket 连接的影响
  • 在生产环境中使用安全的 WebSocket 连接(wss://)

常见问题

Q: WebSocket 连接失败怎么办?

A: 检查网络连接、服务器地址、认证信息是否正确,查看控制台错误信息。

Q: 消息发送失败如何处理?

A: SDK 会自动将失败的消息放入缓存池,当连接恢复时会自动重发。

Q: 如何确保消息按顺序处理?

A: WebSocket 保证消息的传输顺序,但应用层需自行处理消息的处理顺序。

Prev
指南
Next
Uni-app SDK