存档七月 2019

汉枫HF2211串口服务器Modbus rtu转Tcp

HF2211连接多个电机保护器(南京斯沃电气)modbus rtu终端,RS485手拉手方式连接。HF2211与AP无线连接,与前端PC进行数据交换。

HF2211支持Modbus rtu转TCP。

Modbus TCP 与 Modbus RTU区别的关键:

1、TCP报文额外增加了6个字节,前两个字节表示序号,第6个字节表示数据长度。

00 08 00 00 00 06 01 03 01 00 00 12

00 08 表示数据包序号;06表示 01起至末尾 (粗体) ,共6个数据。

2、modbus格式相同,TCP不需要写CRC字节。

汉枫官方并没有C/Python/Nodejs等高级语言使用 RTU转TCP的sample,不方便新人使用。

如上图,PC要读取电机保护器1的数据,可以使用socket拼原始数据,也可以使用现成的lib。如nodejs的modbus-serial包。

使用串口跟踪:

客户端发出数据:

00 08 00 00 00 06 01 03 01 00 00 12

HF2211会自动提取rtu数据部分,并计算出crc附加在数据末尾,写到串口。

https://item.taobao.com/item.htm?spm=a230r.1.14.143.1c4d9d94ia7DBH&id=551231218347&ns=1&abbucket=6#detail

使用串口助手查看,注意勾选 16进制显示。

01 03 01 00 00 12 C4 3B 

H2211设置如下:

1、通讯设置: 协议 TCP Server

2、串口设置: 缓存时间100ms;协议 Modbus

VPS主机注册优惠,可以架ShadowsocksR服务
注册支付10美元即送50美元,期限1个月,可以试验。点此体验

注意,若串口缓存时间10ms,则使用03功能,只能读取1个数据,读取多个数据无返回。

南京斯沃电机保护器,读0100起始0x12个字节,A相电流,。。。

00 00 00 00 00 06 01 03 01 00 00 12

发送12字节,收到45字节。

00 00 00 00 00 27 01 03 24 01 17 01 13 01 23 00 0e 00 00 00 00 00 00 13 84 01 1a 00 00 00 00 01 17 01 13 01 23 00 0e 01 1a 00 39 00 02 

总结:

Modbus RTU设备与PC之间,加入汉枫HF2211以后,PC端高级编程,直接将RTU设备当做TCP设备即可。

modbus crc16 function

modbus crc16计算函数

node.js 版:

function crc16(buffer) {
    var crc = 0xFFFF;
    var odd;

    for (var i = 0; i < buffer.length; i++) {
        crc = crc ^ buffer[i];

        for (var j = 0; j < 8; j++) {
            odd = crc & 0x0001;
            crc = crc >> 1;
            if (odd) {
                crc = crc ^ 0xA001;
            }
        }
    }

    return crc;
};

Highcharts 动态数据曲线图

html页面通过mqtt获取动态数据。

extends layout

block content
  h1= title
  p Welcome to #{title}
  div 1线压力:
    span(id='Line_1' class='badge badge-pill badge-primary')
  div 2线压力:
    span(id='Line_2' class='badge badge-pill badge-info')
  div(
    id='container_1'
    style='min-width:400px;height:400px'
  ) 
  div(
    id='container_2'
    style='min-width:400px;height:400px'
  ) 

append scripts
  script(src='https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.slim.js')

  script(src='javascripts/highcharts.js')
  script(src='javascripts/exporting.js')
  script(src='javascripts/highcharts-ZH_CN.js')

  script.   
    //data 
    let _x = 0;
    let _y = 0;
    let _name = '';

    var chart_1 = {};  
    var chart_2 = {};
    //let uri = 'http://' + document.domain + ':' + location.port + '/';
    let uri = 'http://192.168.1.100:8086/';
    var socket = io(uri);
    socket.on('connect', function(){
      console.log('已连接');

      socket.on('hi', function(msg){
        console.log(msg);
      });

      socket.on('pressure', function(msg){
        //console.log(msg.nm+':'+msg.dt);
        $('#' + msg.nm).html(msg.p);
        let dt = new Date(msg.dt);
        _x = Date.UTC(dt.getFullYear(), dt.getMonth(), dt.getDate(), dt.getHours(), dt.getMinutes(), dt.getSeconds());
        _y = msg.p;
        _name = msg.nm;

        let series = {};
        let chart = {};
        if (_name === 'Line_1') {          
          series = chart_1.series[0];
          chart = chart_1;
        }
        if (_name === 'Line_2') {
          series = chart_2.series[0];
          chart = chart_2;
        }
        series.addPoint([_x, _y], true, true);
        let points = series.points;
        chart.tooltip.refresh(points[points.length -1]);
      });

      socket.on('disconnect', function(){
        console.log('失去连接');
      });
    });

    //charts 
    Highcharts.setOptions({
      global: {
        useUTC: true,
      } });

    chart_1 = Highcharts.chart('container_1', {
      chart: {
        type: 'spline',
        marginRight: 10,
        events: {
          load: function () {
            // load evt
          }
        }
      },
      title: {
        text: '1线压力'
      },
      xAxis: {
        type: 'datetime',
        title: {
          text: null
        }
      },
      yAxis: {
        title: {
          text: null
        }
      },
      tooltip: {
        formatter: function () {
          return '<b>' + this.series.name + '</b><br/>' +
            Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
            Highcharts.numberFormat(this.y, 2);
        }
      },
      legend: {
        enabled: false
      },
      series: [
        {
          name: '1线数据',
          data: [0,1,1,1,1,1,1,1,1,1,1,1,1,1],
        }
      ]
    });

    chart_2 = Highcharts.chart('container_2', {
      chart: {
        type: 'spline',
        marginRight: 10,
        events: {
          load: function () {
            // load evt
          }
        }
      },
      title: {
        text: '2线压力'
      },
      xAxis: {
        type: 'datetime',
        title: {
          text: null
        }
      },
      yAxis: {
        title: {
          text: null
        }
      },
      tooltip: {
        formatter: function () {
          return '<b>' + this.series.name + '</b><br/>' +
            Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
            Highcharts.numberFormat(this.y, 2);
        }
      },
      legend: {
        enabled: false
      },
      series: [
        {
          name: '2线数据',
          data: [0,1,1,1,1,1,1,1,1,1,1,1,1,1],
        }
      ]
    });

Date.UTC函数,It returns the number of milliseconds since January 1, 1970, 00:00:00 UTC。

Highcharts X轴,时间轴,识别ms数值。

useUTC 需要为true,值为false时,会出现8小时的偏差。

windows10 home edition add Hyper-V

windows10 家庭版 增加Hyper-V。

安装docker需要启用Hyper-V。

使用记事本粘贴命令:

pushd "%~dp0"

dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.txt

for /f %%i in ('findstr /i . hyper-v.txt 2^>nul') do dism /online /norestart /add-package:"%SystemRoot%\servicing\Packages\%%i"

del hyper-v.txt

Dism /online /enable-feature /featurename:Microsoft-Hyper-V-All /LimitAccess /ALL

保存为hyper.cmd,注意后缀。

在hyper-v.cmd文件上点击右键,‘以管理员身份运行’。 命令执行到结束,按 Y

win10小娜搜索 Hyper-V,H字母使用大写搜索。

pug 入门指南

UI框架选择bootstrap4

layout.pug,基本模板,公共部分。

doctype html
html
  head
    title= title
    meta(name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no")
    link(rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous")
  body(class='container')
    block content

script(src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous")
script(src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous")
script(src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous")

block scripts

pug使用缩进,表达元素间的包含关系。习惯以后,页面还是很清理、干净的。

extends layout

block content
  h2= title 
  div(id="carouselExampleSlidesOnly" class="carousel slide" data-ride="carousel")
    div(class="carousel-inner")
      // 集中
      div(class="carousel-item active" data-interval="2000" data-pause=false)
        h2 集中计数 집중 계수
        h2 F1 
        table(class="table")
          each val in  data_area_1
            if val.k.startsWith('F1')
              tr
                td
                  span(class='badge badge-pill badge-primary') #{val.k}
                td 
                  span(id=val.k+'_11') #{val.dy} 
                  br/ 
                  span(id=val.k+'_1') #{val.dy_0}
                td 
                  span(id=val.k+'_12') #{val.nt} 
                  br/ 
                  span(id=val.k+'_2') #{val.nt_0}
                td 
                  span(id=val.k+'_10') #{val.total}
                  br/ 
                  span(id=val.k) #{val.total_0}
        h2 F2
        table(class="table")
          each val in  data_area_1
            if val.k.startsWith('F2')
              tr
                td
                  span(class='badge badge-pill badge-info') #{val.k}
                td  
                  span(id=val.k+'_12') #{val.dy} 
                  br/  
                  span(id=val.k+'_2') #{val.dy_0}
                td  
                  span(id=val.k+'_11') #{val.nt} 
                  br/  
                  span(id=val.k+'_1') #{val.nt_0}
                td  
                  span(id=val.k+'_10') #{val.total}
                  br/  
                  span(id=val.k) #{val.total_0}    
      // 分立 
      div(class="carousel-item" data-interval="2000" data-pause=false)
        h2 分立计数 분립 계수
        h2 F1 
        table(class="table")
          each val in  data_area_2
            if val.k.startsWith('F1')
              tr
                td
                  span(class='badge badge-pill badge-primary') #{val.k}
                td  
                  span(id=val.k+'_12') #{val.dy} 
                  br/  
                  span(id=val.k+'_2') #{val.dy_0}
                td  
                  span(id=val.k+'_11') #{val.nt} 
                  br/  
                  span(id=val.k+'_1') #{val.nt_0}
                td  
                  span(id=val.k+'_10') #{val.total}
                  br/  
                  span(id=val.k) #{val.total_0}
        h2 F2
        table(class="table")
          each val in  data_area_1
            if val.k.startsWith('F2')
              tr
                td
                  span(class='badge badge-pill badge-info') #{val.k}
                td  
                  span(id=val.k+'_12') #{val.dy} 
                  br/  
                  span(id=val.k+'_2') #{val.dy_0}
                td  
                  span(id=val.k+'_11') #{val.nt} 
                  br/  
                  span(id=val.k+'_1') #{val.nt_0}
                td  
                  span(id=val.k+'_10') #{val.total}
                  br/  
                  span(id=val.k) #{val.total_0}                      

append scripts
  script(src='https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.slim.js')
  script.
    $('.carousel').carousel();

渲染后的html代码。

<!DOCTYPE html>
<html>
<head><title>生产计数</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
          integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body class="container"><h2>生产计数</h2>
<div class="carousel slide" id="carouselExampleSlidesOnly" data-ride="carousel">
    <div class="carousel-inner"><!-- 集中-->
        <div class="carousel-item active" data-interval="2000"><h2>集中计数 집중 계수</h2>
            <h2>F1 </h2>
            <table class="table">
                <tr>
                    <td><span class="badge badge-pill badge-primary">F1切帽</span></td>
                    <td><span id="F1切帽_11">715 </span><br/> <span id="F1切帽_1">39</span></td>
                    <td><span id="F1切帽_12">-635 </span><br/> <span id="F1切帽_2">0</span></td>
                    <td><span id="F1切帽_10">80</span><br/> <span id="F1切帽">0</span></td>
                </tr>
                <tr>
                    <td><span class="badge badge-pill badge-primary">F1加工</span></td>
                    <td><span id="F1加工_11">0 </span><br/> <span id="F1加工_1">0</span></td>
                    <td><span id="F1加工_12">0 </span><br/> <span id="F1加工_2">0</span></td>
                    <td><span id="F1加工_10">0</span><br/> <span id="F1加工">0</span></td>
                </tr>
                <tr>
                    <td><span class="badge badge-pill badge-primary">F1正面</span></td>
                    <td><span id="F1正面_11">3895 </span><br/> <span id="F1正面_1">324</span></td>
                    <td><span id="F1正面_12">-3548 </span><br/> <span id="F1正面_2">0</span></td>
                    <td><span id="F1正面_10">347</span><br/> <span id="F1正面">0</span></td>
                </tr>
                <tr>
                    <td><span class="badge badge-pill badge-primary">F1涂装半成品</span></td>
                    <td><span id="F1涂装半成品_11">1690 </span><br/> <span id="F1涂装半成品_1">207</span></td>
                    <td><span id="F1涂装半成品_12">0 </span><br/> <span id="F1涂装半成品_2">0</span></td>
                    <td><span id="F1涂装半成品_10">0</span><br/> <span id="F1涂装半成品">0</span></td>
                </tr>
                <tr>
                    <td><span class="badge badge-pill badge-primary">F1涂装成品</span></td>
                    <td><span id="F1涂装成品_11">595 </span><br/> <span id="F1涂装成品_1">0</span></td>
                    <td><span id="F1涂装成品_12">0 </span><br/> <span id="F1涂装成品_2">0</span></td>
                    <td><span id="F1涂装成品_10">0</span><br/> <span id="F1涂装成品">0</span></td>
                </tr>
                <tr>
                    <td><span class="badge badge-pill badge-primary">F1亚克力入口</span></td>
                    <td><span id="F1亚克力入口_11">3296 </span><br/> <span id="F1亚克力入口_1">252</span></td>
                    <td><span id="F1亚克力入口_12">0 </span><br/> <span id="F1亚克力入口_2">0</span></td>
                    <td><span id="F1亚克力入口_10">0</span><br/> <span id="F1亚克力入口">0</span></td>
                </tr>
                <tr>
                    <td><span class="badge badge-pill badge-primary">F1亚克力出口</span></td>
                    <td><span id="F1亚克力出口_11">2799 </span><br/> <span id="F1亚克力出口_1">222</span></td>
                    <td><span id="F1亚克力出口_12">0 </span><br/> <span id="F1亚克力出口_2">0</span></td>
                    <td><span id="F1亚克力出口_10">0</span><br/> <span id="F1亚克力出口">0</span></td>
                </tr>
            </table>
            <h2>F2</h2>
            <table class="table">
                <tr>
                    <td><span class="badge badge-pill badge-info">F2涂装成品</span></td>
                    <td><span id="F2涂装成品_12">1747 </span><br/> <span id="F2涂装成品_2">199</span></td>
                    <td><span id="F2涂装成品_11">-1723 </span><br/> <span id="F2涂装成品_1">0</span></td>
                    <td><span id="F2涂装成品_10">24</span><br/> <span id="F2涂装成品">0    </span></td>
                </tr>
                <tr>
                    <td><span class="badge badge-pill badge-info">F2旋压</span></td>
                    <td><span id="F2旋压_12">531 </span><br/> <span id="F2旋压_2">1556</span></td>
                    <td><span id="F2旋压_11">-486 </span><br/> <span id="F2旋压_1">0</span></td>
                    <td><span id="F2旋压_10">45</span><br/> <span id="F2旋压">0    </span></td>
                </tr>
            </table>
        </div><!-- 分立 -->
        <div class="carousel-item" data-interval="2000"><h2>分立计数 분립 계수</h2>
            <h2>F1 </h2>
            <table class="table">
                <tr>
                    <td><span class="badge badge-pill badge-primary">F1热处理2线</span></td>
                    <td><span id="F1热处理2线_12">1292 </span><br/> <span id="F1热处理2线_2">64</span></td>
                    <td><span id="F1热处理2线_11">-1150 </span><br/> <span id="F1热处理2线_1">0</span></td>
                    <td><span id="F1热处理2线_10">142</span><br/> <span id="F1热处理2线">0</span></td>
                </tr>
                <tr>
                    <td><span class="badge badge-pill badge-primary">F1加工_分立</span></td>
                    <td><span id="F1加工_分立_12">2561 </span><br/> <span id="F1加工_分立_2">107</span></td>
                    <td><span id="F1加工_分立_11">-2326 </span><br/> <span id="F1加工_分立_1">0</span></td>
                    <td><span id="F1加工_分立_10">235</span><br/> <span id="F1加工_分立">0</span></td>
                </tr>
            </table>
            <h2>F2</h2>
            <table class="table">
                <tr>
                    <td><span class="badge badge-pill badge-info">F2涂装成品</span></td>
                    <td><span id="F2涂装成品_12">1747 </span><br/> <span id="F2涂装成品_2">199</span></td>
                    <td><span id="F2涂装成品_11">-1723 </span><br/> <span id="F2涂装成品_1">0</span></td>
                    <td><span id="F2涂装成品_10">24</span><br/> <span id="F2涂装成品">0                      </span></td>
                </tr>
                <tr>
                    <td><span class="badge badge-pill badge-info">F2旋压</span></td>
                    <td><span id="F2旋压_12">531 </span><br/> <span id="F2旋压_2">1556</span></td>
                    <td><span id="F2旋压_11">-486 </span><br/> <span id="F2旋压_1">0</span></td>
                    <td><span id="F2旋压_10">45</span><br/> <span id="F2旋压">0                      </span></td>
                </tr>
            </table>
        </div>
    </div>
</div>
</body>
</html>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
        integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
        crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
        integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
        crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
        integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
        crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.slim.js"></script>
<script>$('.carousel').carousel();</script>

使用pycharm,新建一html文件,然后在菜单code->reform,整理html成可阅读形式。

e3 1220v3优化设置

e3 1220v3 4核4线程,单核性能好于ryzen 1600x。

win7系统即可自动睿频,最低8倍频,4核最高33倍频。

待机时,最低运行在8倍频,速度越800MHZ,CPU温度低,28、9度(室温25)。但是,打开Chrome应用,开网页,有明显卡顿。

CPU睿频不是越低越好,从0.8G加速到3.1G(4核只能睿频到3.3G),还是需要加速时间。

路径: 控制面板-》电源选项-》更改高级电源设置-》处理器电源管理

在win7系统,限制最小速度为40%,约1.3GHZ。另外最大99%,取消超频。

开网页、应用,速度明显提高,而且避免CPU段时间内加速,而速度过充,导致温度高,散热风扇转速提高、噪音增加。

待机温度比先前提高约2摄氏度,风扇为全铝intel普通风扇,室内无空调冷气。

过分追求低功耗,低温度,只是纸面频率数据好看,但会降低体验。

How to add Swap Space on Ubuntu 18.04

Ubuntu 18.04增加交换空间 swap

vultr,1核1G云主机,安装wordpress,启用了1个content主题。(体验传送门

mysql会因为内存不足,而终止。使用free -m查看:

free的内存数量已经很少了
[Note] InnoDB: Initializing buffer pool, total size = 128M, instances = 1, chunk size = 128M
[ERROR] InnoDB: mmap(137428992 bytes) failed; errno 12

除了修改root@vultr:/etc/mysql/mysql.conf.d#下的mysqld.cnf:

innodb_buffer_pool_size = 32M

另一个办法是:增加SWAP文件。

Before continuing with this tutorial, check if your Ubuntu installation already has swap enabled by typing:

检查Ubuntu安装是否已经启用swap:

sudo swapon --show

If the output is empty, it means that your system does not have swap space enabled.

如果无输出信息,说明系统中无启用交换空间。

Otherwise, if you get something like below, you already have swap enabled on your machine.

否则,会看到信息如下:

NAME TYPE SIZE USED PRIO
/swapfile file 1024M 0B -2

Although possible, it is not common to have multiple swap spaces on a single machine.

在单个机器上,通常不需要多个交换分区。

Creating a Swap File

创建交换文件

The user you are logged in as must have sudo privileges to be able to activate swap. In this guide, we will add 1G of swap, if you want to add more swap, replace 1G with the size of the swap space you need.

以管理员身份登录。本例中增加1G的交换分区。尺寸选择依据:可以选择内存数量的2倍。

Perform the steps below to add swap space on Ubuntu 18.04.

01. Start by creating a file which will be used for swap:

01. 创建交换文件

sudo fallocate -l 1G /swapfile

If fallocate is not installed or you get an error message saying fallocate failed: Operation not supported then use the following command to create the swap file:

如果没有安装fallocate,可以使用下面命令替代:

sudo dd if=/dev/zero of=/swapfile bs=1024 count=1048576

02. Only the root user should be able to write and read the swap file. Set the correct permissions by typing:

02. 只有root用户可以读写交换文件,设置正确的权限。

sudo chmod 600 /swapfile

03. Use the mkswap utility to set up a Linux swap area on the file:

03. 格式化文件,若遗漏,则后续步骤会提示 invalid header

sudo mkswap /swapfile

04. Activate the swap file using the following command:

04. 激活交换文件

sudo swapon /swapfile

To make the change permanent open the /etc/fstab file:

添加到/etc/fstab文件:

sudo nano /etc/fstab

在文件末尾粘贴:

/swapfile swap swap defaults 0 0

05. Verify that the swap is active by using either the swapon or the free command as shown below:

05. 验证

sudo swapon --show
sudo free -h
-h 开关,使output能让人看懂

Adjusting the Swappiness Value

调节交换值

Swappiness is a Linux kernel property that defines how often the system will use the swap space. Swappiness can have a value between 0 and 100. A low value will make the kernel to try to avoid swapping whenever possible while a higher value will make the kernel to use the swap space more aggressively.

Swappiness 用来定义系统使用交换空间的频率。取值范围:0-100 。值越小,linux核心积极避免使用交换文件(类似windows的虚拟内存)。

The default swappiness value is 60. You can check the current swappiness value by typing the following command:

默认值是60,可以修改此值。

cat /proc/sys/vm/swappiness

Nodejs: Sequelize query sample

目标:

计数,按类型分组,求最大值。

数据模型:

class Logger extends Sequelize.Model { }
Logger.init({
    id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
    },
    number: { type: Sequelize.INTEGER },
    ts: { type: Sequelize.DATE },
    created: { type: Sequelize.DATE },
    type: { type: Sequelize.STRING },
    factory: { type: Sequelize.INTEGER }
},
    {
        sequelize,
        modelName: 'myData',
        timestamps: false
    });

查询:

let day_data = function (dt) {

  // 时间计算
  // let dt_current = moment().format('YYYY-MM-DD HH:mm:ss');
  let dt_type = typeof dt;
  assert.equal('string', dt_type);

  let dt_c = moment.utc(dt);
  let dt_Str = dt_c.get('year')
    + '-' + dt_c.get('month')
    + '-' + dt_c.get('day')
    + ' ' + _DAY_START;

  let day_start = moment.utc(dt_Str, 'YYYY-M-D HH');
  let day_end = moment.utc(dt_Str, 'YYYY-M-D HH').add(12, 'hours');
  //day_end.add(12, 'hours');

  const Op = db.Sequelize.Op;
  db.Logger.findAll({
    attributes: ['type', [db.sequelize.fn('MAX', db.sequelize.col('number')), 'sum']],
    where: {
      ts: {
        [Op.between]: [day_start, day_end]
      }
    },
    group: 'type'
  })
    .then(projects => {
      console.log(projects);
    });

  const Logger = db.Logger;

}

Sequelize形成的查询命令:

SELECT "type", MAX("number") AS "sum" FROM "myData" AS "myData" WHERE "myData"."ts" BETWEEN '2019-03-01 19:00:00.000 +00:00' AND '2019-03-01 19:00:00.000 +00:00' GROUP BY "type";

查询打印结果:

 myData {
    dataValues: { type: '亚克力入口', sum: 2905 },
    _previousDataValues: { type: '亚克力入口', sum: 2905 },
    _changed: {},
    _modelOptions: {
      timestamps: false,
      validate: {},
      freezeTableName: false,
      underscored: false,
      paranoid: false,
      rejectOnEmpty: false,
      whereCollection: [Object],
      schema: null,
      schemaDelimiter: '',
      defaultScope: {},
      scopes: {},
      indexes: [],
      name: [Object],
      omitNull: false,
      sequelize: [Sequelize],
      hooks: {}
    },
    _options: {
      isNewRecord: false,
      _schema: null,
      _schemaDelimiter: '',
      raw: true,
      attributes: [Array]
    },
    isNewRecord: false
  },