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小程序开发框架配置项,将来能够提供更多的实用组件。

相关文章
|
2月前
|
存储 安全 小程序
在微信小程序中使用 Vant 时如何确保数据的安全?
在微信小程序中使用 Vant 时如何确保数据的安全?
36 1
|
2月前
|
物联网 Linux C#
一键掌控未来!用 Uno Platform 打造跨平台 IoT 应用,轻松连接你的智能设备,让生活更智能!
微软的开源跨平台框架 Uno Platform 支持使用 C# 和 XAML 一次性编写代码并部署至多个平台,如 Windows、macOS、Linux、WebAssembly 及 iOS/Android,这使其成为 IoT 设备开发的理想选择。本文通过创建控制网络 LED 灯的应用,详细介绍了 Uno Platform 的环境搭建及 MQTT 客户端配置过程,实现了 LED 状态订阅与控制指令发送功能。该案例展示了 Uno Platform 在 IoT 领域的潜力及其跨平台优势,未来可扩展至更多设备类型,构建智能家居系统。
281 58
|
18天前
|
存储 缓存 开发框架
提高微信小程序的应用速度
【10月更文挑战第21天】提高微信小程序的应用速度需要从多个方面入手,综合运用各种优化手段。通过不断地优化和改进,能够显著提升小程序的性能,为用户带来更流畅、更高效的使用体验。
35 3
|
1月前
|
移动开发 小程序 数据可视化
基于npm CLI脚手架的uniapp项目创建、运行与打包全攻略(微信小程序、H5、APP全覆盖)
基于npm CLI脚手架的uniapp项目创建、运行与打包全攻略(微信小程序、H5、APP全覆盖)
213 3
|
1月前
|
小程序 前端开发 JavaScript
微信小程序全栈开发中的PWA技术应用
【10月更文挑战第3天】微信小程序作为新兴应用形态,凭借便捷体验与社交传播能力,成为企业拓展业务的新渠道。本文探讨了微信小程序全栈开发中的PWA技术应用,包括离线访问、后台运行、桌面图标及原生体验等方面,助力开发者提升小程序性能与用户体验。PWA技术在不同平台的兼容性、性能优化及用户体验是实践中需注意的关键点。
59 5
|
1月前
|
小程序 JavaScript 开发工具
|
16天前
|
SQL 监控 物联网
ClickHouse在物联网(IoT)中的应用:实时监控与分析
【10月更文挑战第27天】随着物联网(IoT)技术的快速发展,越来越多的设备被连接到互联网上,产生了海量的数据。这些数据不仅包含了设备的状态信息,还包括用户的使用习惯、环境参数等。如何高效地处理和分析这些数据,成为了一个重要的挑战。作为一位数据工程师,我在一个物联网项目中深入使用了ClickHouse,以下是我的经验和思考。
40 0
|
1月前
|
缓存 小程序 UED
如何利用小程序的生命周期函数实现数据的加载和更新?
如何利用小程序的生命周期函数实现数据的加载和更新?
62 4
|
1月前
|
移动开发 小程序 数据可视化
微信小程序可视化开发工具之动态数据
微信小程序可视化开发工具之动态数据
41 3
|
2月前
|
小程序 开发者
微信小程序之网络数据请求 wx:request的简单使用
这篇文章介绍了微信小程序中如何使用wx.request进行网络数据请求,包括请求的配置、请求的格式以及如何在开发阶段关闭请求的合法检验。
微信小程序之网络数据请求 wx:request的简单使用