IoT小程序在展示中央空调采集数据和实时运行状态上的应用

简介: IoT小程序框架在跨系统平台(AliOS Things、Ubuntu、Linux、MacOS、Window等)方面提供了非常优秀的基础能力,应用的更新升级提供了多种方式,在实际业务开发过程中可以灵活选择。IoT小程序框架通过JSAPI提供了调用系统底层应用的能力,同时提供了自定义JSAPI扩展封装的方法,这样就足够业务开发通过自定义的方式满足特殊的业务需求。IoT小程序在前端框架能力、应用框架能力、图形框架能力都进行了适配和优化。那么接下来,我们按照其官方步骤搭建开发环境,然后结合中央空调数据采集和状态显示的实际应用场景开发物联网小程序应用。

  利用前端语言实现跨平台应用开发似乎是大势所趋,跨平台并不是一个新的概念,“一次编译、到处运行”是老牌服务端跨平台语言Java的一个基本特性。随着时代的发展,无论是后端开发语言还是前端开发语言,一切都在朝着减少工作量,降低工作成本的方向发展。
  与后端开发语言不同,利用前端语言实现跨平台有先天的优势,比如后端语言Java跨平台需要将源代码编译为class字节码文件后,再放进 Java 虚拟机运行;而前端语言JavaScript是直接将源代码放进JavaScript解释器运行。这就使得以JavaScript为跨平台语言开发的应用,可移植性非常强大。
  目前跨平台技术按照解决方案分类,主要分为 Web 跨平台、容器跨平台、小程序跨平台。这里,我们主要以小程序跨端为例,测试对比IoT小程序和其他小程序在开发和应用上的优缺点。说到小程序,大家肯定想到微信小程序,实际在各大互联网公司:支付宝、百度、头条等等都有自己的小程序,小程序跨平台和Web跨平台十分类似,都是基于前端语言实现,小程序跨平台的优势在于可以调用系统底层能力,例如:蓝牙、相机等,性能方面也优于Web跨平台。
  IoT小程序和大多数小程序一样,它是一套跨平台应用显示框架,它利用JS语言低门槛和API标准化大幅度降低了IoT应用的研发难度,其官方框架介绍如下:

IOT小程序架构图

  IoT小程序在前端框架能力、应用框架能力、图形框架能力都进行了适配和优化。那么接下来,我们按照其官方步骤搭建开发环境,然后结合中央空调数据采集和状态显示的实际应用场景开发物联网小程序应用。

一、IoT小程序开发环境搭建

  IoT小程序开发环境搭建一共分为四步,对于前端开发来说,安装NodeJS、配置cnpm、安装VSCode都是轻车熟路,不需要细讲,唯一不同的是按照官方说明安装IoT小程序的模拟器和VSCode开发插件HaaS UI,前期开发环境准备完毕,运行Demo查看一下效果,然后就可以进行IoT小程序应用开发了。

搭建开发环境,安装HaaS UI插件和运行新建项目,出现一下界面说明开发环境搭建成功,就可以进行IoT小程序开发了:

项目运行

二、开发展示中央空调采集数据和运行状态的IoT小程序应用

  • 应用场景

  中央空调的维保单位会对中央空调进行定期维护保养,定期的维护保养可排出故障隐患,减少事故发生,降低运行费用,延长设备的使用寿命,同时保障正常的工作时序。除了定期的维护保养外,还需要实时监测中央空调的运行参数(温度、累计排污量、不锈钢_腐蚀率等)和运行状态,及时发现中央空调运行过程中某些参数低于或高于报警值的问题,以便及时定位诊断中央空调存在的问题,然后进行相应的维护保养操作。

  • 架构实现

  中央空调的数据采集和展示是典型的物联网应用架构,在中央空调端部署采集终端,通过Modbus通信协议采集中央空调设备参数,然后再由采集终端通过MQTT消息发送的我们的云端服务器,云端服务器接收到MQTT消息后转发到消息队列Kafka中,由云服务器上的自定义服务应用订阅Kafka主题,再存储到我们时序数据库中。

下图展示了物联网应用的整体架构和IoT小程序在物联网架构中的位置:

中央空调物联网

  IoT小程序框架作为跨平台应用显示框架,顾名思义,其在物联网应用中主要作为显示框架开发。在传统应用中,我们使用微信小程序实现采集数据和运行状态的展示。而IoT小程序支持部署在AliOS Things、Ubuntu、Linux、MacOS、Window等系统中,这就使得我们可以灵活的将IoT小程序部署到多种设备终端中运行。
  下面将以阿里云ASP-80智显面板为例,把展示中央空调采集数据和运行状态的IoT小程序部署在阿里云ASP-80智显面板中。

  • IoT小程序开发

  我们将从IoT小程序提供的前端框架能力、应用框架能力、图形框架能力来规划相应的功能开发。
  IoT小程序采用Vue.js(v2.6.12)开源框架,实现了W3C标准的标签和样式子集;定义了四个应用生命周期,分别是:onLaunch,onShow,onHide,onDestroy;定义了十四个前端基础组件,除了基础的CSS样式支持外,还提供了对Less的支持;Net网络请求通过框架内置的JSAPI实现。
  为了快速熟悉IoT小程序框架的开发方式,我们将在VSCode中导入官方公版案例,并以公版案例为基础框架开发我们想要的功能。
简单实现通过网络请求获取中央空调采集数据并展示:
1、在VSCode编辑器中导入从IoT小程序官网下载的公版案例,下载地址
2、因为IoT小程序前端框架使用的是Vue.js框架,所以在新增页面时也是按照Vue.js框架的模式,将页面添加到pages目录。我们是空调项目的IoT小程序,所以这里在pages目录下新增air-conditioning目录用于存放空调IoT小程序相关前端代码。

新增前端代码目录

3、在app.json中配置新增的页面,修改pages项,增加"air-conditioning": "pages/air-conditioning/index.vue"。

{
"pages": {
  ......
  "air-conditioning": "pages/air-conditioning/index.vue",
    ......
    },
    "options": {
    "style": {
      "theme": "theme-dark"
    }
  }
}

4、在air-conditioning目录下新增index.vue前端页面代码,用于展示空调的采集数据是否正常及历史曲线图。设计需要开发的界面如下,页面的元素有栅格布局、Tabs 标签页、Radio单选框、日期选择框、曲线图表等元素。

采集数据

曲线图表

5、首先是实现Tabs标签页,IoT小程序没有Tabs组件,只能自己设置多个Text组件自定义样式并添加click事件来实现。

  <div class="tab-list">
  <fl-icon name="back" class="nav-back" @click="onBack" />
    <text
      v-for="(item, index) in scenes"
      :key="index"
      :class="'tab-item' + (index === selectedIndex ? ' tab-item-selected' : '')"
      @click="tabSelected(index)"
      >{{ item }}</text
                   >
</div>
  ......
  data() {
    return {
      scenes: ["设备概览", "实时数据", "数据统计", "状态统计"],
      selectedIndex: 0
    };
  },
  ......

Tabs实现效果

6、添加采集数据显示列表,在其他小程序框架中,尤其是以Vue.js为基础框架的小程序框架,这里有成熟的组件,而IoT小程序也是需要自己来实现。

<template>
  <div class="scene-wrapper" v-if="current">
    <div class="label-temperature-wrapper top-title">
      <div class="label-temperature-wrapper left-text">
        <text class="label-temperature">设备编码:</text>
        <text class="label-temperature-unit">{{deviceNo}}</text>
      </div>
      <div class="label-temperature-wrapper right-text">
        <text class="label-temperature">数据日期:</text>
        <text class="label-temperature-unit">{{collectTime}}</text>
      </div>
    </div>
    <div class="main-wrapper">
      <div class="section">
        <div class="demo-block icon-block">
          <div class="icons-item" v-for="(value, key, index) in IconTypes" :key="index">
            <div class="label-title-wrapper">
              <text class="label-title left-text">{{paramName}}</text>
              <text class="label-title-unit right-text" style="padding-right: 5px;">{{paramWarn}}</text>
            </div>
            <div class="label-zhibiao-wrapper">
              <text class="label-zhibiao">当前值:</text>
              <text class="label-zhibiao-unit">{{value}}</text>
            </div>
            <div class="label-zhibiao-wrapper" style="margin-bottom: 10px;">
              <text class="label-zhibiao">目标值:</text>
              <text class="label-zhibiao-unit">{{targetValue}}</text>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

采集数据展示界面

  在开发过程中发现,IoT小程序对样式的支持不是很全面,本来想将组件放置在同一行,一般情况下,只需要使用标准CSS样式display: inline就可以实现,但这里没有效果只能通过Flexbox进行布局在同一行。在设置字体方面,本来想把采集数据显示的描述字段加粗,用于突出显示,但是使用CSS样式font-weight无效,无论是设置数值还是blod,没有一点加粗效果。
7、界面实现之后,需要发送数据请求,来查询采集数据并显示在界面上。IoT小程序通过框架内置JSAPI的Net网络提供网络请求工具。目前从官方文档和代码中来看,官方框架只提供了http请求,没有提供物联网中常用的WebSocket和MQTT工具,估计需要自定义扩展系统JSAPI实现其他网络请求。

 created() {
  const http = $falcon.jsapi.http
  http.request({
    url: 'http://服务域名/device/iot/query/data/point',
    data: {
      'deviceNo': '97306000000000005',
      'rangeType': 'mo',
      'lastPoint': '1',
      'beginDateTime': '2023-02-10+16:09:42',
      'endDateTime': '2023-03-12+16:09:42'
    },
    header: {
      'Accept': 'application/json;charset=UTF-8',
      'Accept-Encoding': 'gzip, deflate, br',
      'Content-Type': 'application/json;charset=UTF-8',
      'Authorization': '有效token'
    }
  }, (response) => {
    console.log(response)
    var obj = JSON.parse(response.result)
    console.log(obj.success)
    console.log(JSON.parse(obj.data))
  });
},

  按照官方要求编写http请求,发现默认未开启https请求:Protocol "https" not supported or disabled in libcurl。切换为http请求,返回数据为乱码,设置Accept-Encoding和Accept为application/json;charset=UTF-8仍然无效,且返回数据为JSON字符串,需要自己手动使用JSON.parse()进行转换,对于习惯于应用成熟框架的人来说,十分不友好。想了解更多关于 $falcon.jsapi.http的相关配置和实现,但是官方文档只有寥寥几句,没有详细的说明如何使用和配置,以及http请求中遇到一些常见问题的解决方式。
8、IoT小程序框架提供画布组件,原则上来讲可以实现常用的曲线图表功能,但是如果使用其基础能力从零开始开发一套图表系统,耗时又耗力,所以这里尝试引入常用的图表组件库ECharts,使用ECharts在IoT小程序上显示曲线图表。

  • 执行cnpm install echarts --save安装echarts组件
cnpm install echarts --save
  • 新建echarts配置文件,按需引入
// 加载echarts,注意引入文件的路径
import echarts from 'echarts/lib/echarts'

// 再引入你需要使用的图表类型,标题,提示信息等
import 'echarts/lib/chart/bar'
import 'echarts/lib/chart/pie'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/title'
import 'echarts/lib/component/tooltip'

export default echarts
  • 新增echarts组件ChartDemo.vue
<template>
    <div ref="chartDemo" style="height:200px;" ></div>
</template>
<script>
  import echarts from '@/utils/echarts-config.js'
  const ChartDemo = {
    name: 'ChartDemo',
    data() {
      return {
        chart: null
      }
    },
    watch: {
      option: {
        handler(newValue, oldValue) {
          this.chart.setOption(newValue)
        },
        deep: true
      }
    },
    mounted() {
      this.chart = echarts.init(this.$refs.chartDemo)
    },
    methods: {
      setOption(option) {
        this.chart && this.chart.setOption(option)
      },
      throttle(func, wait, options) {
        let time, context, args
        let previous = 0
        if (!options) options = {}
  
        const later = function() {
          previous = options.leading === false ? 0 : new Date().getTime()
          time = null
          func.apply(context, args)
          if (!time) context = args = null
        }
  
        const throttled = function() {
          const now = new Date().getTime()
          if (!previous && options.leading === false) previous = now
          const remaining = wait - (now - previous)
          context = this
          args = arguments
          if (remaining <= 0 || remaining > wait) {
            if (time) {
              clearTimeout(time)
              time = null
            }
            previous = now
            func.apply(context, args)
            if (!time) context = args = null
          } else if (!time && options.trailing !== false) {
            time = setTimeout(later, remaining)
          }
        }
        return throttled
      }
    }
  }
  export default ChartDemo
</script>
  
  
  • 在base-page.js中注册全局组件
......
import ChartDemo from './components/ChartDemo.vue';
export class BasePage extends $falcon.Page {
  constructor() {
    super()
  }
  beforeVueInstantiate(Vue) {
    ......
    Vue.component('ChartDemo', ChartDemo);
  }
}
  • 新建空调采集数据展示页history-charts.vue,用于展示Echarts图表
<template>
  <div class="scene-wrapper" v-if="current">
    <div class="brightness-wrap">
      <ChartBlock ref="chart2"></ChartBlock>
    </div>
  </div>
</template>

<script>
  let option2 = {
    title: {
      text: '中央空调状态图',
      subtext: '运行状态占比',
      left: 'center'
    },
    tooltip: {
      trigger: 'item',
      formatter: '{a} <br/>{b} : {c} ({d}%)'
    },
    legend: {
      orient: 'vertical',
      left: 'left',
      data: ['开机', '关机', '报警', '故障', '空闲']
    },
    series: [
      {
        name: '运行状态',
        type: 'pie',
        radius: '55%',
        center: ['50%', '60%'],
        data: [
          { value: 335, name: '开机' },
          { value: 310, name: '关机' },
          { value: 234, name: '报警' },
          { value: 135, name: '故障' },
          { value: 1548, name: '空闲' }
        ],
        emphasis: {
          itemStyle: {
            shadowBlur: 10,
            shadowOffsetX: 0,
            shadowColor: 'rgba(0, 0, 0, 0.5)'
          }
        }
      }
    ]
  }

  export default {
    props:{
      current:{
        type:Boolean,
        default:false
      }
    },
    data() {
      return {
      };
    },
    methods: {
    },
    mounted: function() {
      this.$refs.chart2.setOption(option2)
    }
  };
</script>
  • 执行HaaS UI: Build-Debug ,显示打包成功

打包成功

  • 执行HaaS UI: Simulator ,显示“当前HaaS UI: Simulator任务正在执行,请稍后再试”

稍后再试

  本来想在模拟器上看一下Echarts显示效果,但是执行HaaS UI: Simulator时一直显示任务正在执行。然后以为是系统进程占用,但是重启、关闭进程等操作一系列操作下来,仍然显示此提示,最后将Echarts代码删除,恢复到没有Echarts的状态,又可以执行了。这里不清楚是否是IoT小程序不支持引入第三方图表组件,从官方文档中没有找到答案。后来又使用echarts的封装组件v-charts进行了尝试,结果依然不能展示。
  如果不能使用第三方组件,那么只能使用IoT官方小程序提供的画布组件来自己实现图表功能,官方提供的画布曲线图示例。
9、通过IoT小程序提供的组件分别实现显示中央空调采集数据的实时数据、数据统计、状态统计图表。
-实现实时数据折线图

<template>
  <div class="scene-wrapper"  v-show="current">
    <div class="main-wrapper">
      <div class="label-temperature-wrapper top-title">
        <div class="label-temperature-wrapper left-text">
          <text class="label-temperature">设备编码:</text>
          <text class="label-temperature-unit">{{deviceNo}}</text>
        </div>
        <div class="label-temperature-wrapper right-text">
          <text class="label-temperature">数据日期:</text>
          <text class="label-temperature-unit">{{collectTime}}</text>
        </div>
      </div>
      <canvas ref="c2" class="canvas" width="650" height="300"></canvas>
    </div>
  </div>
</template>

<script>
  export default {
    name: "canvas",
    props: {},
    data() {
      return {
        deviceNo: '97306000000000005',
        collectTime: '2023-03-11 23:59:59'
      };
    },
    mounted() {
      this.c2();
    },
    methods: {
      c2() {
        let ctx = typeof createCanvasContext === "function" ? createCanvasContext(this.$refs.c2) : this.$refs.c1.getContext("2d");
        // Demo测试数据
        let arr = [{key:'01:00',value:61.68},{key:'02:00',value:83.68},{key:'03:00',value:56.68},{key:'04:00',value:86.68},{key:'05:00',value:53.68},
                   {key:'06:00',value:41.68},{key:'07:00',value:33.68}];
        this.drawStat(ctx, arr);
      },
      //该函数用来绘制折线图
      drawStat(ctx, arr) {
        //画布的款高
        var cw = 700;
        var ch = 300;
        //内间距padding
        var padding = 35;
        //原点,bottomRight:X轴终点,topLeft:Y轴终点
        var origin = {x:padding,y:ch-padding};
        var bottomRight = {x:cw-padding,y:ch-padding};
        var topLeft = {x:padding,y:padding};

        ctx.strokeStyle='#FF9500';
        ctx.fillStyle='#FF9500';

        //绘制X轴
        ctx.beginPath();
        ctx.moveTo(origin.x,origin.y);
        ctx.lineTo(bottomRight.x,bottomRight.y);
        //绘制X轴箭头
        ctx.lineTo(bottomRight.x-10,bottomRight.y-5);
        ctx.moveTo(bottomRight.x,bottomRight.y);
        ctx.lineTo(bottomRight.x-10,bottomRight.y+5);
        //绘制Y轴
        ctx.moveTo(origin.x,origin.y);
        ctx.lineTo(topLeft.x,topLeft.y);
        //绘制Y轴箭头
        ctx.lineTo(topLeft.x-5,topLeft.y+10);
        ctx.moveTo(topLeft.x,topLeft.y);
        ctx.lineTo(topLeft.x+5,topLeft.y+10);

        //设置字号
        var color = '#FF9500';
        ctx.fillStyle=color;
        ctx.font = "13px scans-serif";//设置字体

        //绘制X方向刻度
        //计算刻度可使用的总宽度
        var avgWidth = (cw - 2*padding - 50)/(arr.length-1);
        for(var i=0;i<arr.length;i++){
          //循环绘制所有刻度线
          if(i > 0){
            //移动刻度起点
            ctx.moveTo(origin.x+i*avgWidth,origin.y);
            //绘制到刻度终点
            ctx.lineTo(origin.x+i*avgWidth,origin.y-10);
          }
          //X轴说明文字:1月,2月...
          var txtWidth = 35;
          ctx.fillText(
            arr[i].key,
            origin.x+i*avgWidth-txtWidth/2 + 10,
            origin.y+20);
        }
          //绘制Y方向刻度
          //最大刻度max
          var max = 0;
          for(var i=0;i<arr.length;i++){
          if(arr[i].value>max){
          max=arr[i].value;
        }
        }
          console.log(max);

          /*var max = Math.max.apply(this,arr);
          console.log(max);*/
          var avgValue=Math.floor(max/5);
          var avgHeight = (ch-padding*2-50)/5;
          for(var i=1;i<arr.length;i++){
          //绘制Y轴刻度
          ctx.moveTo(origin.x,origin.y-i*avgHeight);
          ctx.lineTo(origin.x+10,origin.y-i*avgHeight);
          //绘制Y轴文字
          var txtWidth = 40;
          ctx.fillText(avgValue*i,
          origin.x-txtWidth-5,
          origin.y-i*avgHeight+6);
        }

          //绘制折线
          for(var i=0;i<arr.length;i++){
          var posY = origin.y - Math.floor(arr[i].value/max*(ch-2*padding-50));
          if(i==0){
          ctx.moveTo(origin.x+i*avgWidth,posY);
        }else{
          ctx.lineTo(origin.x+i*avgWidth,posY);
        }
          //具体金额文字
          ctx.fillText(arr[i].value,
          origin.x+i*avgWidth,
          posY
          )
        }
          ctx.stroke();
          //绘制折线上的小圆点
          ctx.beginPath();
          for(var i=0;i<arr.length;i++){
          var posY = origin.y - Math.floor(arr[i].value/max*(ch-2*padding-50));
          ctx.arc(origin.x+i*avgWidth,posY,4,0,Math.PI*2);//圆心,半径,画圆
          ctx.closePath();
        }
          ctx.fill();
        }
      }
    };
</script>

实时数据折线图

-数据统计图表

<template>
  <div class="scene-wrapper"  v-show="current">
    <div class="main-wrapper">
      <div class="label-temperature-wrapper top-title">
        <div class="label-temperature-wrapper left-text">
          <text class="label-temperature">设备编码:</text>
          <text class="label-temperature-unit">{{deviceNo}}</text>
        </div>
        <div class="label-temperature-wrapper right-text">
          <text class="label-temperature">数据日期:</text>
          <text class="label-temperature-unit">{{collectTime}}</text>
        </div>
      </div>
      <canvas ref="c1" class="canvas" width="650" height="300"></canvas>
    </div>
  </div>
</template>
<script>
  export default {
    name: "canvas",
    props: {},
    data() {
      return {
        deviceNo: '97306000000000005',
        collectTime: '2023-03-13 20:23:36'
      };
    },
    mounted() {
      this.c1();
    },
    methods: {
      c1() {
        let ctx = typeof createCanvasContext === "function" ? createCanvasContext(this.$refs.c1) : this.$refs.c1.getContext("2d");
        this.draw(ctx);
      },
      draw(ctx){
        var x0=30,//x轴0处坐标
          y0=280,//y轴0处坐标
          x1=700,//x轴顶处坐标
          y1=30,//y轴顶处坐标
          dis=30;
        //先绘制X和Y轴
        ctx.beginPath();
        ctx.lineWidth=1; 
        ctx.strokeStyle='#FF9500';
        ctx.fillStyle='#FF9500';
        ctx.moveTo(x0,y1);//笔移动到Y轴的顶部
        ctx.lineTo(x0,y0);//绘制Y轴
        ctx.lineTo(x1,y0);//绘制X轴
        ctx.stroke();

        //绘制虚线和Y轴值  
        var yDis = y0-y1;
        var n=1;
        ctx.fillText(0,x0-20,y0);//x,y轴原点显示0
        while(yDis>dis){
          ctx.beginPath();
          //每隔30划一个虚线
          ctx.setLineDash([2,2]);//实线和空白的比例
          ctx.moveTo(x1,y0-dis);
          ctx.lineTo(x0,y0-dis);
          ctx.fillText(dis,x0-20,y0-dis);
          //每隔30划一个虚线
          dis+=30;
          ctx.stroke();
        }

        var xDis=30,//设定柱子之前的间距
          width=40;//设定每个柱子的宽度
        //绘制柱状和在顶部显示值
        for(var i=0;i<12;i++){//假设有8个月
          ctx.beginPath();
          var color = '#' + Math.random().toString(16).substr(2, 6).toUpperCase();//随机颜色
          ctx.fillStyle=color;
          ctx.font = "13px scans-serif";//设置字体

          var height = Math.round(Math.random()*220+20);//在一定范围内随机高度

          var rectX=x0+(width+xDis)*i,//柱子的x位置
            rectY=height;//柱子的y位置
          ctx.color='#FF9500';
          ctx.fillText((i+1)+'月份',rectX,y0+15);//绘制最下面的月份稳住

          ctx.fillRect(rectX,y0, width, -height);//绘制一个柱状

          ctx.fillText(rectY,rectX+10,280-rectY-5);//显示柱子的值
        }
      },
    }
  };
</script>

数据统计图表

-状态统计图表

<template>
  <div class="scene-wrapper"  v-show="current">
    <div class="main-wrapper">
      <div class="label-temperature-wrapper top-title">
        <div class="label-temperature-wrapper left-text">
          <text class="label-temperature">设备编码:</text>
          <text class="label-temperature-unit">{{deviceNo}}</text>
        </div>
        <div class="label-temperature-wrapper right-text">
          <text class="label-temperature">数据日期:</text>
          <text class="label-temperature-unit">{{collectTime}}</text>
        </div>
      </div>
      <canvas ref="c3" class="canvas" width="600" height="300"></canvas>
    </div>
  </div>
</template>
<script>
  export default {
    name: "canvas",
    props: {},
    data() {
      return {
        deviceNo: '97306000000000005',
        collectTime: '2023-03-13 20:29:36'
      };
    },
    mounted() {
      this.c3();
    },
    methods: {
      c3() {
        let ctx = typeof createCanvasContext === "function" ? createCanvasContext(this.$refs.c3) : this.$refs.c3.getContext("2d");
        this.drawPie(ctx);
      },
      drawPie(pen){
        // Demo测试数据
        var deg = Math.PI / 180
        var arr = [
          {
            name: "开机",
            time: 8000,
            color: '#7CFF00'
          },
          {
            name: "关机",
            time: 1580,
            color: '#737F9C'
          },
          {
            name: "空闲",
            time: 5790,
            color: '#0ECC9B'
          },
          {
            name: "故障",
            time: 4090,
            color: '#893FCD'
          },
          {
            name: "报警",
            time: 2439,
            color: '#EF4141'
          },
        ];
        //总价
        pen.translate(30,-120);
        arr.tatol = 0;
        for (let i = 0; i < arr.length; i++) {
          arr.tatol = arr.tatol + arr[i].time
        }
        var stardeg = 0
        arr.forEach(el => {
          pen.beginPath()
          var r1 = 115
          pen.fillStyle = el.color
          pen.strokeStyle='#209AAD';
          pen.font = "15px scans-serif";
          //求出每个time的占比
          var angle = (el.time / arr.tatol) * 360
          //利用占比来画圆弧
          pen.arc(300, 300, r1, stardeg * deg, (stardeg + angle) * deg)
          //将圆弧与圆心相连接,形成扇形
          pen.lineTo(300, 300)
          var r2 = r1+10;
          if(el.name === '关机' || el.name === '空闲')
          {
            r2 = r1+30
          }
          //给每个扇形添加数组的name
          var y1 = 300 + Math.sin((stardeg + angle) * deg-angle*deg/2 ) *( r2)
          var x1 = 300 + Math.cos((stardeg + angle) * deg-angle*deg/2 ) * (r2)
          pen.fillText(`${el.name}`, x1, y1)
          stardeg = stardeg + angle
          pen.fill()
          pen.stroke()
        });
      },
    }
  };
</script>

状态统计图表

三、将IoT小程序更新到ASP-80智显面板查看运行效果

  将IoT小程序更新到ASP-80智显面板,在硬件设备上查看IoT应用运行效果。如果是使用PC端初次连接,那么需要安装相关驱动和配置,否则无法使用VSCode直接更新IoT小程序到ASP-80智显面板。
1、如果使用Win10将IoT小程序包更新到ASP-80智显面板上,必须用到CH340串口驱动,第一次通过TypeC数据线连接设备,PC端设备管理器的端口处不显示端口,这时需要下载Windows版本的CH340串口驱动下载链接

不显示端口

下载链接

2、将下载的驱动文件CH341SER.ZIP解压并安装之后,再次查看PC端设备管理器端口就有了USB Serial CH340端口。

驱动安装成功

USB Serial CH340端口

3、使用SourceCRT连接ASP-80智显面板,按照官方文档说明,修改配置文件,连接好WiFi无线网,下一步通过VSCode直接更新IoT小程序到ASP-80智显面板上查看测试。

连接ASP-80智显面板

获取ASP-80智显面板的IP地址

4、所有准备工作就绪后,点击VSCode的上传按钮HaaS UI: Device,将应用打包并上传至ASP-80智显面板。在选择ip地址框的时候,输入我们上一步获取到的ip地址192.168.1.112,其他参数保持默认即可,上传成功后,VSCode控制台提示安装app成功。

app安装成功提示

5、IoT小程序安装成功之后就可以在ASP-80智显面板上查看运行效果了。
设备概览

实时数据

数据统计

状态统计

  综上所述,IoT小程序框架在跨系统平台(AliOS Things、Ubuntu、Linux、MacOS、Window等)方面提供了非常优秀的基础能力,应用的更新升级提供了多种方式,在实际业务开发过程中可以灵活选择。IoT小程序框架通过JSAPI提供了调用系统底层应用的能力,同时提供了自定义JSAPI扩展封装的方法,这样就足够业务开发通过自定义的方式满足特殊的业务需求。
  虽然多家互联网公司都提供了小程序框架,但在128M 128M这样的低资源设备里输出,IoT小程序是比较领先的,它不需要另外下载APP作为小程序的容器,降低了资源的消耗,这一点是其他小程序框架所不能比拟的。
  但是在前端框架方面,实用组件太少。其他小程序已发展多年,基于基础组件封装并开源的前端组件应用场景非常丰富,对于中小企业来说,习惯于使用成熟的开源组件,如果使用IoT小程序开发物联网应用可能需要耗费一定的人力物力。既然是基于Vue.js的框架,却没有提供引入其他优秀组件的文档说明和示例,不利于物联网应用的快速开发,希望官方能够完善文档,详细说明IoT小程序开发框架配置项,将来能够提供更多的实用组件。

相关文章
|
23天前
|
小程序 JavaScript
小程序中的数据双向绑定和Vue的有什么区别
小程序中的数据双向绑定和Vue的有什么区别
|
2月前
|
小程序 JavaScript
【微信小程序】-- 自定义组件 - 数据监听器 (三十四)
【微信小程序】-- 自定义组件 - 数据监听器 (三十四)
|
2月前
|
存储 小程序 JavaScript
【微信小程序】-- 自定义组件 -- 数据、方法和属性(三十三)
【微信小程序】-- 自定义组件 -- 数据、方法和属性(三十三)
|
3月前
|
JSON 小程序 数据安全/隐私保护
小程序动态调试-解密加密数据与签名校验
本文主要讲解微信小程序加密、验签的情况下如何进行动态调试已获取签名以及加密信息
|
18天前
|
小程序 前端开发 JavaScript
微信小程序全栈开发中的PWA技术应用
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中PWA技术的应用,PWA结合Web的开放性和原生应用的性能,提供离线访问、后台运行、桌面图标和原生体验。开发者可利用Service Worker实现离线访问,Worker处理后台运行,Web App Manifest添加桌面图标,CSS和JavaScript提升原生体验。实践中需注意兼容性、性能优化和用户体验。PWA技术能提升小程序的性能和用户体验,助力开发者打造优质小程序。
|
18天前
|
存储 弹性计算 小程序
小程序全栈开发中的云函数应用实践
【4月更文挑战第12天】本文探讨了小程序全栈开发中云函数的应用实践,云函数作为轻量级后端服务,具备弹性伸缩、安全可靠和跨平台支持等特点。开发者可利用云函数实现用户认证、数据存储、文件上传下载、第三方服务集成及定时任务等功能。实践中需注意性能优化、安全性及成本控制,以提升小程序性能和用户体验。通过云函数,开发者能更高效地进行全栈开发。
|
18天前
|
小程序 JavaScript 前端开发
微信小程序全栈开发中的数据交互与渲染优化
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的数据交互与渲染优化,旨在提升小程序性能和用户体验。数据交互涉及GET、POST、PUT和DELETE请求,优化措施包括使用HTTPS、数据压缩、缓存及限流。渲染优化则涵盖虚拟DOM、减少DOM操作、组件化和模板使用,以及WXSS样式设计和媒体查询。利用性能监控工具可识别并优化性能瓶颈。开发者应综合运用这些策略,持续优化小程序。
|
23天前
|
存储 小程序 开发者
如何提升微信小程序的应用速度
如何提升微信小程序的应用速度
|
2月前
|
关系型数据库 Serverless 分布式数据库
Serverless 应用引擎常见问题之在抖音快手小程序上使用如何解决
Serverless 应用引擎(Serverless Application Engine, SAE)是一种完全托管的应用平台,它允许开发者无需管理服务器即可构建和部署应用。以下是Serverless 应用引擎使用过程中的一些常见问题及其答案的汇总:
22 3
|
2月前
|
小程序
【微信小程序】-- 自定义组件 - 数据监听器 - 案例 (三十五)
【微信小程序】-- 自定义组件 - 数据监听器 - 案例 (三十五)

热门文章

最新文章