github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/mappers/modbus_mapper/src/devicetwin.js (about)

     1  const constant = require('./constant');
     2  const common = require('./common');
     3  const Buffer = require('buffer').Buffer;
     4  const uuidv4 = require('uuid/v4');
     5  const util = require('util');
     6  const async = require('async');
     7  
     8  class DeviceTwin {
     9      constructor(mqttClient) {
    10          this.mqttClient = mqttClient;
    11      }
    12      
    13      // transferType transfer data according to the dpl configuration
    14      transferType(visitor, property, data, callback) {
    15          let transData;
    16          async.waterfall([
    17              function(callback) {
    18                  if (visitor.visitorConfig.isRegisterSwap) {
    19                      common.switchRegister(data, (switchedData)=>{
    20                          callback(null, switchedData);
    21                      });
    22                  } else {
    23                      callback(null, data);
    24                  }
    25              },
    26              function(internalData, callback) {
    27                  if (visitor.visitorConfig.isSwap && (visitor.visitorConfig.register === 'HoldingRegister' || visitor.visitorConfig.register === 'InputRegister')) {
    28                      common.switchByte(internalData, (switchedData)=>{
    29                          callback(null, switchedData);
    30                      });
    31                  } else {
    32                      callback(null, internalData);
    33                  }
    34              }
    35          ], function(err, transedData) {
    36              transData = transedData;
    37          });
    38          this.transferDataType(visitor, property, transData, callback);
    39      }
    40  
    41      // transferDataType transfer data according to the dpl configuration
    42      transferDataType(visitor, property, data, callback) {
    43          let transData;
    44          switch(property.dataType) {
    45              case 'int':
    46              case 'float':
    47                  if (visitor.visitorConfig.register === 'DiscreteInputRegister' || visitor.visitorConfig.register === 'CoilRegister') {
    48                      common.bitArrayToInt(data, (num)=>{
    49                          transData = num;
    50                      });
    51                  } else if (visitor.visitorConfig.register === 'HoldingRegister' || visitor.visitorConfig.register === 'InputRegister') {
    52                      common.twoByteArrayToInt(data, (num)=>{
    53                          transData = num;
    54                      })
    55                  }
    56  
    57                  if (visitor.visitorConfig.scale !=0 && transData != null) {
    58                      transData = transData * visitor.visitorConfig.scale;
    59                  }
    60  
    61                  if (property.dataType === 'int') {
    62                      transData = parseInt(transData);
    63                  }
    64  
    65                  if (property.maximum !== null && transData > parseFloat(property.maximum)) {
    66                      logger.info("read data is larger than max value, use max value")
    67                      transData = parseInt(property.maximum);
    68                  } else if (property.minimum !== null && transData < parseFloat(property.minimum)) {
    69                      logger.info("read data is smaller than min value, use min value")
    70                      transData = parseInt(property.minimum);
    71                  }
    72  
    73                  callback(transData);
    74                  break;
    75              case 'string':
    76                  let buf = new Buffer.from(data);
    77                  transData = buf.toString('utf8')
    78                  callback(transData);
    79                  break;
    80              case 'boolean':
    81                  if (data[0] == 0 || data[0] == 1){
    82                      transData = Boolean(data[0]);
    83                  } else {
    84                      transData = null;
    85                  }
    86                  callback(transData);
    87                  break;
    88              default:
    89                  logger.error('unknown dataType: ', property.dataType);
    90                  callback(null);
    91                  break;    
    92          }
    93      }
    94  
    95      // updateActual update actual value to edge mqtt
    96      updateActual(deviceID, property, value) {
    97          let reply_msg = {
    98              event_id: "",
    99              timestamp: new Date().getTime()
   100          };
   101          let twin = {};
   102          twin[property.name] = {
   103              actual: {
   104                  value: String(value),
   105                  metadata: {
   106                      timestamp: new Date().getTime()
   107                  }
   108              },
   109              metadata: {
   110                  tyep: property.dataType
   111              }
   112          };
   113          reply_msg.twin = twin;
   114          this.mqttClient.publish(constant.defaultTopicPrefix + deviceID + constant.twinUpdateTopic, JSON.stringify(reply_msg));
   115      }
   116  
   117      // dealUpdate set latest actual value of devicetwin into actualVal map
   118      dealUpdate(transData, property, deviceID, actualVals) {
   119          if (!actualVals.has(util.format("%s-%s", deviceID, property.name))) {
   120              this.updateActual(deviceID, property, transData);
   121              actualVals.set(util.format("%s-%s", deviceID, property.name), String(transData));
   122              logger.info("update devicetwin[%s] of device[%s] successfully", property.name, deviceID);
   123          } else {
   124              this.compareActuals(transData, actualVals.get(util.format("%s-%s", deviceID, property.name)), (changed)=>{
   125                  if (changed) {
   126                      this.updateActual(deviceID, property, transData);
   127                      actualVals.set(util.format("%s-%s", deviceID, property.name), String(transData));
   128                      logger.info("update devicetwin[%s] of device[%s] successfully", property.name, deviceID);
   129                  }
   130              });
   131          }
   132      }
   133  
   134      // getActuals publish get devicetwin msg to edge mqtt
   135      getActuals(deviceID) {
   136          let payload_msg = {
   137              event_id: "",
   138              timestamp: new Date().getTime()
   139          };
   140          this.mqttClient.publish(constant.defaultTopicPrefix + deviceID + constant.twinGetTopic, JSON.stringify(payload_msg));
   141      }
   142  
   143      // setActuals set device property and actual value map
   144      setActuals(getMsg, callback) {
   145          let deviceTwin = getMsg.twin;
   146          let PropActuals = new Map();
   147          Object.keys(deviceTwin).forEach(function(key){
   148              if (deviceTwin[key].hasOwnProperty('actual')) {
   149                  PropActuals.set(key, deviceTwin[key].actual.value);
   150              }
   151          })
   152          callback(PropActuals);
   153      }
   154  
   155      // setExpecteds set device property and expected value map
   156      setExpecteds(getMsg, callback) {
   157          let deviceTwin = getMsg.twin;
   158          let ProExpect = new Map();
   159          Object.keys(deviceTwin).forEach(function(key){
   160              if (deviceTwin[key].hasOwnProperty('expected') && !deviceTwin[key].hasOwnProperty('actual') || JSON.stringify(deviceTwin[key].actual) == '{}') {
   161                  ProExpect.set(key, deviceTwin[key].expected.value);
   162              }
   163          })
   164          callback(ProExpect);
   165      }
   166  
   167      // compareActuals compare if data is changed
   168      compareActuals(data, cachedActuals, callback) {
   169          let changed = false;
   170          if (data != cachedActuals) {
   171              changed = true;
   172          }
   173          callback(changed);
   174      }
   175  
   176      // UpdateDirectActuals update all devicetwin property to edge mqtt
   177      UpdateDirectActuals(devIns, deviceID, actualVals) {
   178          if (devIns.has(deviceID)) {
   179              let deviceName = devIns.get(deviceID).name;
   180              this.generateDirectGetMsg(deviceName, deviceID, actualVals, (directGetMsg)=>{
   181                  this.mqttClient.publish(constant.defaultDirectTopicPrefix + deviceID + constant.directGetTopic, JSON.stringify(directGetMsg));
   182              });
   183          }
   184      }
   185  
   186      // generateDirectGetMsg generate Direct Get Msg in message format
   187      generateDirectGetMsg(deviceName, deviceID, actualVals, callback) {
   188          let header = {
   189              msg_id: uuidv4(),
   190              parent_msg_id: "",
   191              timestamp: new Date().getTime(),
   192              sync: false
   193          };
   194          let route = {
   195              source: "eventbus",
   196              group: "",
   197              operation: "upload",
   198              resource: util.format("%s%s%s", constant.defaultDirectTopicPrefix, deviceID, constant.directGetTopic)
   199          };
   200          let content = {
   201              data: actualVals,
   202              device_name: deviceName,
   203              device_id: deviceID,
   204              timestamp: new Date().getTime()
   205          };
   206          let directGetMsg = {
   207              header: header,
   208              route: route,
   209              content: content
   210          };
   211          callback(directGetMsg);
   212      }
   213  
   214      // syncExpected check whether expected value should be update to device
   215      static syncExpected(delta, key, callback) {
   216          let deviceTwin = delta.twin[key];
   217          if (!delta.twin.hasOwnProperty(key)) {
   218              logger.error("Invalid device twin ", key);
   219              return;
   220          }
   221          if (!deviceTwin.hasOwnProperty('actual') ||
   222            (deviceTwin.hasOwnProperty('expected') && deviceTwin.expected.hasOwnProperty('metadata') && deviceTwin.actual.hasOwnProperty('metadata') && 
   223              deviceTwin.expected.metadata.timestamp > deviceTwin.actual.metadata.timestamp &&
   224              deviceTwin.expected.value !== deviceTwin.actual.value)) {
   225            callback(deviceTwin.expected.value);
   226          }
   227      }
   228  }
   229  
   230  module.exports = DeviceTwin;