基于 Node.js + Express

更新时间:2018-07-03 23:41:08

本文将以开发一个 RGB智能灯的服务端应用为例,介绍第三方服务端应用的开发过程,方案基于 Node.js 和 express 框架。

前期准备

软件安装

开发过程

初始化应用目录

一、安装 Express 应用生成器,执行:

npm install -g express-generator

二、创建应用目录,执行:

express rgb-light

完成目录创建:

image.png | left | 557x600

进入项目目录并安装依赖:

cd rgb-light
npm install

三、 启动应用本地调试服务

在项目目录下执行:

npm run start

image.png | left | 666x114

四、访问应用

用浏览器访问:

http://127.0.0.1:3000/

可以看到页面上输出了 “Welcome to Express”:

image.png | left | 481x323

PS:由于Express比较灵活,模板引擎选用可能不一致,可根据实际项目需要进行相应的修改。本教程中使用的模板引擎是express-generator自动生成使用的Jade。

代码开发

一、安装 aliyun-api-gateway ,在项目目录执行:

npm install --save aliyun-api-gateway

二、添加配置项

在 public/javascript目录新增gateway.js 文件,将前一步申请到的 AK、AS 添加到配置项,方便后续使用,然后配置aliyun-api-gateway, 代码如下:

const Client = require('aliyun-api-gateway').Client;

const config = (appInfo => {
  const config = exports = {};

  // use for cookie sign key, should change to your own and keep security
  config.keys = appInfo.name + '_1526880651009_8352';

  // 配置 appKey、appSecret
  config.appKey = '24900114';
  config.appSecret = 'b36854ed91674b0da7fbfa59514ef2e5';

  return config;
})('yourAppName');

module.exports ={
  getClient() {
    if (!this.client) {
      // 使用配置中的 AppKey 以及 AppSecret 创建阿里云 API 网关 Client
      this.client = new Client(config.appKey, config.appSecret);
    }
    return this.client;
  },

  post: async function(apiPath, apiVer, params) {
    const client = this.getClient();
    let response = null;
    try {
      // LinkDevelop 平台的 URL 为 http://api.link.aliyun.com
      // 该地址可以在 LinkDevelop 平台的资源管理》官方服务中通过查看 API 详情得到
      const apiurl = 'https://api.link.aliyun.com' + apiPath;
      const payload = {
        data: {
          id: new Date() * 1 + '',
          version: '1.0',
          request: {
            apiVer: apiVer || '',
          },
          params,
        },
      };
      response = await client.post(apiurl, payload);
    } catch (error) {
      console.error('API Response Error', error);
      response = error;
    }
    return response || {};
  }
}

新增 light.js文件,用于表示我们的 rgb-light,记得将 productKey 和 deviceName 换成设备开发步骤中的测试设备,并保证设备在线(例如打开 http://web-device.oss-cn-hangzhou.aliyuncs.com/index.html 这个页面,并保持设备上线):

var apiclient = require('./gateway');
var express = require('express');
var app = express();

// 设备 id 使用设备开发中注册的测试设备,并保持设备在线
const thingId = {
  productKey: 'a1YfvmKLmXP', //<productKey>
  deviceName: 'A4Wi85YYXlM3a7pKPB8T' // <deviceName>
};

module.exports = {
  getProperties: async function() {
    // 获取设备属性
    const ret = await apiclient.post(
      '/thing/device/properties/query',
      '1.1.0',
      thingId
    );
    var info = '';
    const properties = {};
    if (ret.code !== 200) {
      info = ret.localizedMsg || ret.message || '连接服务器失败';
    } else {
      info = '已连接到服务器';
      properties = ret.data && ret.data[0] && ret.data[0].value;
      console.log(properties);
      // 设置到程序中
      app.locals.properties = properties;
    }
    // 数据整理并返回
    return {
      info: info,
      color: {
        Red: (properties && properties.Red) || '',
        Green: (properties && properties.Green) || '',
        Blue: (properties && properties.Blue) || ''
      }
    };
  },
  setProperties: async function(properties) {
    var prop = Object.assign({}, properties);
    // 设置设备属性
    const ret = await apiclient.post('/thing/device/properties/set', '1.1.0', {
      ...thingId,
      properties: {
        RGBColor: prop
      }
    });
    console.log(ret);
    var info = '';
    if (ret.code !== 200) {
      info = ret.localizedMsg || ret.message || '设置失败';
    } else {
      info = '设置成功';
      // 设置到本地配置中
      app.locals.properties = properties;
    }
    // 数据整理并返回
    return {
      info: info,
      color: {
        Red: (properties && properties.Red) || '',
        Green: (properties && properties.Green) || '',
        Blue: (properties && properties.Blue) || ''
      }
    };
  }
};

三、修改 views/index.jade 模板文件,写入模板内容:

extends layout

block content
  h1= title
  p #{info}
  form(id='lightEdit',method='post',action='/')
    p R:
      input(id="red", name ='Red', value='#{color && color.Red || ""}')
    p G:
      input(id="green", name = 'Green', value= '#{color && color.Green || ""}')
    p B:
      input(id="blue", name='Blue',  value='#{color && color.Blue || ""}')
    input(type='submit' class='setButton' value='set')

三、修改 routes/index.js 文件,读取服务器端的配置内容:

var express = require('express');
var router = express.Router();
var light = require('../public/javascripts/light.js');
/* GET home page. */
router.get('/', function(req, res, next) {
  var lightData = light.getProperties();
  lightData.then(resolve => {
    res.render('index', { title: 'RGB light', info: resolve.info, color: resolve.color});
  }).catch(err => {
    console.error(err);
    res.render('index', { title: 'RGB light', info: err, color: err.color});  
  })
});

module.exports = router;

四、修改 app.js文件,监听提交的 form表单(其中 jade模板中 form的action路径要跟 app.use的路径一致,本例中为“/”):

//加在文件顶部
var light = require('./public/javascripts/light');

//....

//加在module.exports = app; 前面
app.post('/', function(req, res, next){
  var prop = {};
  for (const key in req.body) {
    if (req.body[key]) {
      prop[key] = parseInt(req.body[key], 10);
    }
    else {
      prop[key] = app.locals.properties && app.locals.properties[key] || '';
    }
  }
  light.setProperties(prop).then( resolve => {
    res.render('index', { title: 'RGB light', info: resolve.info , color: resolve.color});
  });
});

用浏览器访问页面:

http://localhost:3000/

就能看到如下界面,说明设备的属性值已经获取成功了(如果没有设置过数据,R G B 可能显示为空值):

image.png | left | 312x331

我们把输入框中的属性值改成其他值之后,点击"set"按钮:

image.png | left | 191x262

点击“设置属性”按钮,待页面刷新后,观察测试设备的日志接收情况,这里以 Web Device 模拟设备为例,可以看到 Web Device 模拟设备成功接收到到云端设置属性的消息:

image.png | left | 747x416

将模拟设备的 RGBColor 属性值改成(255,255,0),点击“上报”,在右侧可以看到设备上报属性成功的消息:

image | left

这时候我们再打开 http://127.0.0.1:3000/ 应用页面,发现属性输入框已获取到最新的值(文案已变成“已连接到服务器”):

image.png | left | 322x363

至此,第三方应用的开发就完成了,那么恭喜你完成了 IoT 应用端到端的全链路开发!

应用发布

目前 Link Develop 没有提供服务端应用的托管能力,请购买阿里云 ECS 或者第三方服务器进行应用托管发布。

注意事项

若出现 “RBAC鉴权失败,没有访问此api的权限 api:1533”, 请确保阅读完(https://yuque.com/linkdevelop/quickstart/exkbdk) 这篇文章的内容。这种情况一般是“物的管理服务”没有开启。
如果设置的时候遇到服务异常,注意字段的校验(如 int 和 string 需要区分开来)。

results matching ""

    No results matching ""