gateway
This commit is contained in:
commit
598ec1c8d9
|
@ -0,0 +1,252 @@
|
|||
### 网关配置文件说明
|
||||
|
||||
## Example:
|
||||
|
||||
{
|
||||
<!-- 网关信息 -->
|
||||
"gateway_info": {
|
||||
<!-- 网关的设备id -->
|
||||
"id": "F23FACD2-7D85-4FCC-88E3-C5B78931A26D",
|
||||
<!-- 网关的版本 -->
|
||||
"version": "yunhorn_gw_c_v1",
|
||||
<!-- 网关的位置信息 -->
|
||||
"localtion": [113.960347, 22.54143],
|
||||
<!-- 网关从属信息 -->
|
||||
"单位": "深圳市云兴科技",
|
||||
<!-- 网关配置,当前只支持厕位配置 -->
|
||||
"config": [{
|
||||
<!-- 开关量检测设备id -->
|
||||
<!-- # 关联id和类型必须在下面的设备列表(devices_list)里面,若不在便不会与数据关联 -->
|
||||
"id": "EC13C2D9-6A93-4894-BB5B-89BDAA786D8A",
|
||||
"version": "yunhorn_kgl_c8_v1",
|
||||
<!-- # 相应的版本的设备检测的数据条目是确定的,不可增减 -->
|
||||
"data": [
|
||||
<!-- 例如: "yunhorn_kgl_c8_v1"检测的数据是8(见设备类型说明),那么如下8个数据,格式为数据,["类型(string)", “位置序号(int)”] -->
|
||||
<!-- 若设备又条目没有关联到相应的厕位,便以此格式[null, null] -->
|
||||
["男厕位", 1],
|
||||
["男厕位", 2],
|
||||
["男厕位", 3],
|
||||
["男厕位", 4],
|
||||
["男厕位", 5],
|
||||
["男厕位", 6],
|
||||
["男厕位", 7],
|
||||
["男厕位", 8]
|
||||
]
|
||||
}, {
|
||||
"id": "82BF7B5E-EC0D-4DB6-807F-B097C3C84073",
|
||||
"version": "yunhorn_kgl_c8_v1",
|
||||
"data": [
|
||||
["母婴", 1],
|
||||
["残卫", 1],
|
||||
["残卫", 2],
|
||||
["男便池", 4],
|
||||
["男便池", 5],
|
||||
["男便池", 6],
|
||||
["男便池", 7],
|
||||
["男便池", 8]
|
||||
]
|
||||
}, {
|
||||
"id": "F5B7FDCC-79A8-499E-A925-F2FF357BE30D",
|
||||
"version": "yunhorn_kgl_c8_v1",
|
||||
"data": [
|
||||
["男厕位", 9],
|
||||
["男厕位", 10],
|
||||
["女厕位", 14],
|
||||
["女厕位", 15],
|
||||
["女厕位", 16],
|
||||
["女厕位", 17],
|
||||
["女厕位", 18],
|
||||
[null, null]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "00DD66A6-378E-450D-98AA-44AC02741980",
|
||||
"version": "yunhorn_kgl_c16_v1",
|
||||
"data": [
|
||||
["女厕位", 1],
|
||||
["女厕位", 2],
|
||||
["女厕位", 3],
|
||||
["女厕位", 4],
|
||||
["女厕位", 5],
|
||||
["女厕位", 6],
|
||||
["女厕位", 7],
|
||||
["女厕位", 8],
|
||||
["女厕位", 9],
|
||||
["女厕位", 10],
|
||||
["女厕位", 11],
|
||||
["女厕位", 12],
|
||||
["女厕位", 13],
|
||||
["男便池", 1],
|
||||
["男便池", 2],
|
||||
["男便池", 3]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
<!-- 设备列表,需要检测的设备,["设备ID(string)","对应的串口(string)","版本号(string)","相同版本设备的编号(string),相同设备的编号不可一样"] -->
|
||||
"devices_list": [
|
||||
["EC13C2D9-6A93-4894-BB5B-89BDAA786D8A", "port3", "yunhorn_kgl_c8_v1", "1"],
|
||||
["52A79B3D-D9D9-48AF-AEB4-7D456BA22B31", "port1", "yunhorn_db_c_v1", "1"],
|
||||
["607E11C4-8986-4F8E-807E-FFA655A6F677", "port1", "yunhorn_sb_c_v1", "1"],
|
||||
["066BB944-AFA2-4E5D-86FA-61D9080A97BB", "port2", "yunhorn_kq_c_v1", "1"],
|
||||
["22E175B2-8DD5-4740-B428-0297F409AA47", "port2", "yunhorn_lhq_c_v1", "1"],
|
||||
["20F44B9C-E4A1-478E-B28F-0B7B14A2AF64", "port2", "yunhorn_aq_c_v1", "1"]
|
||||
],
|
||||
<!-- 串口列表,串口参数配置, -->
|
||||
"serialports_list": {
|
||||
"port1": {
|
||||
"com": "/dev/ttyUSB2",
|
||||
"bauds": 2400,
|
||||
"size": 8,
|
||||
"parity": "E",
|
||||
"stopbits": 1,
|
||||
"readtimeout": 1,
|
||||
"note": "水表电表"
|
||||
},
|
||||
"port2": {
|
||||
"com": "/dev/ttyUSB1",
|
||||
"bauds": 9600,
|
||||
"size": 8,
|
||||
"parity": "N",
|
||||
"stopbits": 1,
|
||||
"readtimeout": 1,
|
||||
"note": "空气质量"
|
||||
},
|
||||
"port3": {
|
||||
"com": "/dev/ttyUSB0",
|
||||
"bauds": 9600,
|
||||
"size": 8,
|
||||
"parity": "N",
|
||||
"stopbits": 1,
|
||||
"readtimeout": 1,
|
||||
"note": "开关量监测"
|
||||
}
|
||||
},
|
||||
<!-- 设备采集命令配置 -->
|
||||
"rs485devices": {
|
||||
"EC13C2D9-6A93-4894-BB5B-89BDAA786D8A": {
|
||||
"version": "yunhorn_kgl_c8_v1",
|
||||
"num": "1",
|
||||
<!-- 采集命令 -->
|
||||
"command": [
|
||||
[1, 2, 0, 0, 0, 1, 185, 202],
|
||||
[1, 2, 0, 1, 0, 1, 232, 10],
|
||||
[1, 2, 0, 2, 0, 1, 24, 10],
|
||||
[1, 2, 0, 3, 0, 1, 73, 202],
|
||||
[1, 2, 0, 4, 0, 1, 248, 11],
|
||||
[1, 2, 0, 5, 0, 1, 169, 203],
|
||||
[1, 2, 0, 6, 0, 1, 89, 203],
|
||||
[1, 2, 0, 7, 0, 1, 8, 11]
|
||||
]
|
||||
},
|
||||
"00DD66A6-378E-450D-98AA-44AC02741980": {
|
||||
"version": "yunhorn_kgl_c16_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[3, 2, 0, 0, 0, 16, 120, 36]
|
||||
]
|
||||
},
|
||||
"52A79B3D-D9D9-48AF-AEB4-7D456BA22B31": {
|
||||
"version": "yunhorn_db_c_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[104, 65, 4, 0, 120, 16, 68, 104, 17, 4, 51, 51, 52, 51, 195, 22]
|
||||
]
|
||||
},
|
||||
"607E11C4-8986-4F8E-807E-FFA655A6F677": {
|
||||
"version": "yunhorn_sb_c_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[104, 16, 103, 19, 146, 128, 1, 0, 0, 1, 3, 31, 144, 2, 186, 22]
|
||||
]
|
||||
},
|
||||
"066BB944-AFA2-4E5D-86FA-61D9080A97BB": {
|
||||
"version": "yunhorn_kq_c_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[2, 3, 0, 0, 0, 7, 4, 59]
|
||||
]
|
||||
},
|
||||
"22E175B2-8DD5-4740-B428-0297F409AA47": {
|
||||
"version": "yunhorn_lhq_c_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[4, 3, 0, 6, 0, 1, 100, 94]
|
||||
]
|
||||
},
|
||||
"20F44B9C-E4A1-478E-B28F-0B7B14A2AF64": {
|
||||
"version": "yunhorn_aq_c_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[3, 3, 0, 0, 0, 1, 133, 232]
|
||||
]
|
||||
}
|
||||
},
|
||||
"iconurl": "http://192.168.3.188/icons/",
|
||||
"websocketurl": ["192.168.3.216:8080", "/echo"],
|
||||
<!-- 服务器接口 -->
|
||||
"post_to_server": "https://smartoilets.cn/socketServer/statis/push",
|
||||
<!-- 关闭调试日志 -->
|
||||
"debug": false
|
||||
}
|
||||
|
||||
## 设备类型说明
|
||||
# 水表:
|
||||
"yunhoron_sb_c_v1":
|
||||
通讯方式: RS485
|
||||
串口配置: 2400 8 E 1
|
||||
串口命令条目: 1
|
||||
数据条目: 1
|
||||
|
||||
# 电表:
|
||||
"yunhoron_db_c_v1":
|
||||
通讯方式: RS485
|
||||
串口配置: 2400 8 E 1
|
||||
串口命令条目: 1
|
||||
数据条目: 1
|
||||
|
||||
# 空气检测仪:
|
||||
"yunhoron_kq_c_v1":
|
||||
通讯方式: RS485
|
||||
串口配置: 9600 8 N 1
|
||||
串口命令条目: 1
|
||||
数据条目: 7
|
||||
|
||||
# 硫化氢检测仪:
|
||||
"yunhoron_lhq_c_v1":
|
||||
通讯方式: RS485
|
||||
串口配置: 9600 8 N 1
|
||||
串口命令条目: 1
|
||||
数据条目: 1
|
||||
|
||||
# 氨气检测仪:
|
||||
"yunhoron_aq_c_v1":
|
||||
通讯方式: RS485
|
||||
串口配置: 9600 8 N 1
|
||||
串口命令条目: 1
|
||||
数据条目: 1
|
||||
|
||||
# 开关量检测:
|
||||
"yunhoron_kgl_c8_v1":
|
||||
通讯方式: RS485
|
||||
串口配置: 9600 8 N 1
|
||||
串口命令条目: 8
|
||||
数据条目: 8
|
||||
|
||||
"yunhoron_kgl_c16_v1":
|
||||
通讯方式: RS485
|
||||
串口配置: 9600 8 N 1
|
||||
串口命令条目: 1
|
||||
数据条目: 16
|
||||
|
||||
## 当前版本说明
|
||||
支持多设备采集,只需将串口参数配置一样的设备放在相对应的串口里面,并配置设备即可
|
||||
目前集成RS485有线通讯,(zigbee,lora未集成)
|
||||
提供api,详见api说明
|
||||
数据解析发送,目前4种数据格式,code1001,code1004,code1005,code1006
|
||||
code1001: 5分钟一次 (设备列表里的所有设备的数据)
|
||||
code1004: 不定时,取决于客流摄像机
|
||||
code1005: 不定时,当设备数据变化时发送该设备数据
|
||||
code1006: 不定时,当有人评价时,发送评价设备的数据给服务器
|
||||
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
{
|
||||
"gateway_info": {
|
||||
"id": "F23FACD2-7D85-4FCC-88E3-C5B78931A26D",
|
||||
"version": "yunhorn_gw_c_v1",
|
||||
"localtion": [113.960347, 22.54143],
|
||||
"单位": "深圳市云兴科技",
|
||||
"config": [{
|
||||
"id": "EC13C2D9-6A93-4894-BB5B-89BDAA786D8A",
|
||||
"version": "yunhorn_kgl_c8_v1",
|
||||
"data": [
|
||||
["男厕位", 1],
|
||||
["男厕位", 2],
|
||||
["男厕位", 3],
|
||||
["男厕位", 4],
|
||||
["男厕位", 5],
|
||||
["男厕位", 6],
|
||||
["男厕位", 7],
|
||||
["男厕位", 8]
|
||||
]
|
||||
}, {
|
||||
"id": "82BF7B5E-EC0D-4DB6-807F-B097C3C84073",
|
||||
"version": "yunhorn_kgl_c8_v1",
|
||||
"data": [
|
||||
["母婴", 1],
|
||||
["残卫", 1],
|
||||
["残卫", 2],
|
||||
["男便池", 4],
|
||||
["男便池", 5],
|
||||
["男便池", 6],
|
||||
["男便池", 7],
|
||||
["男便池", 8]
|
||||
]
|
||||
}, {
|
||||
"id": "F5B7FDCC-79A8-499E-A925-F2FF357BE30D",
|
||||
"version": "yunhorn_kgl_c8_v1",
|
||||
"data": [
|
||||
["男厕位", 9],
|
||||
["男厕位", 10],
|
||||
["女厕位", 14],
|
||||
["女厕位", 15],
|
||||
["女厕位", 16],
|
||||
["女厕位", 17],
|
||||
["女厕位", 18],
|
||||
[null, null]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "00DD66A6-378E-450D-98AA-44AC02741980",
|
||||
"version": "yunhorn_kgl_c16_v1",
|
||||
"data": [
|
||||
["女厕位", 1],
|
||||
["女厕位", 2],
|
||||
["女厕位", 3],
|
||||
["女厕位", 4],
|
||||
["女厕位", 5],
|
||||
["女厕位", 6],
|
||||
["女厕位", 7],
|
||||
["女厕位", 8],
|
||||
["女厕位", 9],
|
||||
["女厕位", 10],
|
||||
["女厕位", 11],
|
||||
["女厕位", 12],
|
||||
["女厕位", 13],
|
||||
["男便池", 1],
|
||||
["男便池", 2],
|
||||
["男便池", 3]
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"devices_list": [
|
||||
["EC13C2D9-6A93-4894-BB5B-89BDAA786D8A", "port3", "yunhorn_kgl_c8_v1", "1"],
|
||||
["52A79B3D-D9D9-48AF-AEB4-7D456BA22B31", "port1", "yunhorn_db_c_v1", "1"],
|
||||
["607E11C4-8986-4F8E-807E-FFA655A6F677", "port1", "yunhorn_sb_c_v1", "1"],
|
||||
["066BB944-AFA2-4E5D-86FA-61D9080A97BB", "port2", "yunhorn_kq_c_v1", "1"],
|
||||
["22E175B2-8DD5-4740-B428-0297F409AA47", "port2", "yunhorn_lhq_c_v1", "1"],
|
||||
["20F44B9C-E4A1-478E-B28F-0B7B14A2AF64", "port2", "yunhorn_aq_c_v1", "1"]
|
||||
],
|
||||
"serialports_list": {
|
||||
"port1": {
|
||||
"com": "/dev/ttyUSB2",
|
||||
"bauds": 2400,
|
||||
"size": 8,
|
||||
"parity": "E",
|
||||
"stopbits": 1,
|
||||
"readtimeout": 1,
|
||||
"note": "水表电表"
|
||||
},
|
||||
"port2": {
|
||||
"com": "/dev/ttyUSB1",
|
||||
"bauds": 9600,
|
||||
"size": 8,
|
||||
"parity": "N",
|
||||
"stopbits": 1,
|
||||
"readtimeout": 1,
|
||||
"note": "空气质量"
|
||||
},
|
||||
"port3": {
|
||||
"com": "/dev/ttyUSB0",
|
||||
"bauds": 9600,
|
||||
"size": 8,
|
||||
"parity": "N",
|
||||
"stopbits": 1,
|
||||
"readtimeout": 1,
|
||||
"note": "开关量监测"
|
||||
}
|
||||
},
|
||||
"rs485devices": {
|
||||
"EC13C2D9-6A93-4894-BB5B-89BDAA786D8A": {
|
||||
"version": "yunhorn_kgl_c8_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[1, 2, 0, 0, 0, 1, 185, 202],
|
||||
[1, 2, 0, 1, 0, 1, 232, 10],
|
||||
[1, 2, 0, 2, 0, 1, 24, 10],
|
||||
[1, 2, 0, 3, 0, 1, 73, 202],
|
||||
[1, 2, 0, 4, 0, 1, 248, 11],
|
||||
[1, 2, 0, 5, 0, 1, 169, 203],
|
||||
[1, 2, 0, 6, 0, 1, 89, 203],
|
||||
[1, 2, 0, 7, 0, 1, 8, 11]
|
||||
]
|
||||
},
|
||||
"00DD66A6-378E-450D-98AA-44AC02741980": {
|
||||
"version": "yunhorn_kgl_c16_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[3, 2, 0, 0, 0, 16, 120, 36]
|
||||
]
|
||||
},
|
||||
"52A79B3D-D9D9-48AF-AEB4-7D456BA22B31": {
|
||||
"version": "yunhorn_db_c_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[104, 65, 4, 0, 120, 16, 68, 104, 17, 4, 51, 51, 52, 51, 195, 22]
|
||||
]
|
||||
},
|
||||
"607E11C4-8986-4F8E-807E-FFA655A6F677": {
|
||||
"version": "yunhorn_sb_c_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[104, 16, 103, 19, 146, 128, 1, 0, 0, 1, 3, 31, 144, 2, 186, 22]
|
||||
]
|
||||
},
|
||||
"066BB944-AFA2-4E5D-86FA-61D9080A97BB": {
|
||||
"version": "yunhorn_kq_c_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[2, 3, 0, 0, 0, 7, 4, 59]
|
||||
]
|
||||
},
|
||||
"22E175B2-8DD5-4740-B428-0297F409AA47": {
|
||||
"version": "yunhorn_lhq_c_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[4, 3, 0, 6, 0, 1, 100, 94]
|
||||
]
|
||||
},
|
||||
"20F44B9C-E4A1-478E-B28F-0B7B14A2AF64": {
|
||||
"version": "yunhorn_aq_c_v1",
|
||||
"num": "1",
|
||||
"command": [
|
||||
[3, 3, 0, 0, 0, 1, 133, 232]
|
||||
]
|
||||
}
|
||||
},
|
||||
"iconurl": "http://192.168.3.188/icons/",
|
||||
"websocketurl": ["192.168.3.216:8080", "/echo"],
|
||||
"post_to_server": "https://smartoilets.cn/socketServer/statis/push",
|
||||
"debug": false
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,115 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type P1001 struct {
|
||||
CODE int `json:"code"`
|
||||
GATEWAY_INFO Gateway_info `json:"gateway_info"`
|
||||
DEVICES []Device `json:"devices"`
|
||||
}
|
||||
|
||||
type P1004_6 struct {
|
||||
CODE uint16 `json:"code"`
|
||||
ID string `json:"id"`
|
||||
VERSION string `json:"version"`
|
||||
ONLINE bool `json:"online"`
|
||||
DATA map[string]interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func send_data(code int, data ...Device) {
|
||||
log.Println("************************************************************************")
|
||||
data_buf := string(build_data(code, data))
|
||||
log.Println(data_buf)
|
||||
post_to_server(data_buf)
|
||||
log.Println("************************************************************************")
|
||||
}
|
||||
|
||||
func build_data(code int, data []Device) []byte {
|
||||
switch code {
|
||||
case 1001:
|
||||
var R_data P1001
|
||||
R_data.CODE = 1001
|
||||
R_data.DEVICES = make([]Device, 0)
|
||||
R_data.GATEWAY_INFO = conf.GATEWAY_INFO
|
||||
DEVICEDATAS.RLock()
|
||||
for _, i := range DEVICEDATAS.DATA {
|
||||
R_data.DEVICES = append(R_data.DEVICES, i)
|
||||
}
|
||||
DEVICEDATAS.RUnlock()
|
||||
data_buf, _ := json.Marshal(R_data)
|
||||
return data_buf
|
||||
case 1004:
|
||||
var R_data P1004_6
|
||||
R_data.CODE = 1004
|
||||
R_data.ID = rl_data.MACADDRESS
|
||||
R_data.VERSION = "hk_kll_v1"
|
||||
R_data.ONLINE = true
|
||||
R_data.DATA = make(map[string]interface{})
|
||||
R_data.DATA["starttime"] = rl_data.PEOPLECOUNTING.TIMERANGE.STARTTIME
|
||||
R_data.DATA["endtime"] = rl_data.PEOPLECOUNTING.TIMERANGE.ENDTIME
|
||||
R_data.DATA["enter"] = rl_data.PEOPLECOUNTING.ENTER
|
||||
R_data.DATA["pass"] = rl_data.PEOPLECOUNTING.PASS
|
||||
R_data.DATA["exit"] = rl_data.PEOPLECOUNTING.EXIT
|
||||
traffic_data.TRAFFIC = traffic_data.TRAFFIC + rl_data.PEOPLECOUNTING.ENTER
|
||||
data_buf, _ := json.Marshal(R_data)
|
||||
return data_buf
|
||||
case 1005:
|
||||
var R_data P1004_6
|
||||
R_data.CODE = 1005
|
||||
R_data.ID = data[0].ID
|
||||
R_data.VERSION = data[0].VERSION
|
||||
R_data.ONLINE = data[0].ONLINE
|
||||
R_data.DATA = data[0].DATA
|
||||
data_buf, _ := json.Marshal(R_data)
|
||||
return data_buf
|
||||
case 1006:
|
||||
var R_data P1004_6
|
||||
R_data.CODE = 1006
|
||||
R_data.ID = pj_data.ID
|
||||
R_data.VERSION = "yunhorn_pj_c_v1"
|
||||
R_data.ONLINE = true
|
||||
R_data.DATA = make(map[string]interface{})
|
||||
R_data.DATA["feedback"] = pj_data.FEEDBACK
|
||||
switch pj_data.FEEDBACK {
|
||||
case "棒棒哒":
|
||||
good++
|
||||
case "没厕纸":
|
||||
bad++
|
||||
case "气味难闻":
|
||||
bad++
|
||||
case "地面湿滑":
|
||||
bad++
|
||||
case "洗手台不洁":
|
||||
bad++
|
||||
case "厕位不洁":
|
||||
bad++
|
||||
case "其他":
|
||||
bad++
|
||||
}
|
||||
satisfaction_data.SATISFACTION = good / (good + bad)
|
||||
data_buf, _ := json.Marshal(R_data)
|
||||
return data_buf
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func post_to_server(post_data string) {
|
||||
url := conf.POST_TO_SERVER
|
||||
payload := strings.NewReader("------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"data\"\r\n\r\n" + post_data + "\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--")
|
||||
req, _ := http.NewRequest("POST", url, payload)
|
||||
req.Header.Add("content-type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW")
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
defer res.Body.Close()
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
log.Println("post_to_server:", string(body))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Weather struct {
|
||||
STATUS string
|
||||
LANG string
|
||||
UNIT string
|
||||
SERVER_TIME uint16
|
||||
LOCATION []float32
|
||||
API_STATUS string
|
||||
TZSHIFT uint16
|
||||
API_VERSION string
|
||||
RESULT Result
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
STATUS string
|
||||
O3 float32
|
||||
CO float32
|
||||
TEMPERATURE float32
|
||||
PM10 float32
|
||||
SKYCON string
|
||||
CLOUDRATE float32
|
||||
AQI float32
|
||||
DSWRF float32
|
||||
VISIBILITY float32
|
||||
HUMIDITY float32
|
||||
SO2 float32
|
||||
ULTRAVIOLET Ultraviolet
|
||||
PRES float32
|
||||
PM25 float32
|
||||
NO2 float32
|
||||
PERCIPITATION Precipitation
|
||||
COMFORT Comfort
|
||||
WIND Wind
|
||||
}
|
||||
|
||||
type Ultraviolet struct {
|
||||
INDEX int
|
||||
DESC string
|
||||
}
|
||||
|
||||
type Precipitation struct {
|
||||
NEAREST Nearest
|
||||
LOCAL Local
|
||||
}
|
||||
|
||||
type Nearest struct {
|
||||
STATUS string
|
||||
DISTANCE float32
|
||||
INTENSITY float32
|
||||
}
|
||||
|
||||
type Local struct {
|
||||
STATUS string
|
||||
INTENSITY int
|
||||
DATASOURCE string
|
||||
}
|
||||
|
||||
type Comfort struct {
|
||||
INDEX int
|
||||
DESC string
|
||||
}
|
||||
|
||||
type Wind struct {
|
||||
DIRECTION float32
|
||||
SPEED float32
|
||||
}
|
||||
|
||||
var iconurl = conf.ICONURL
|
||||
|
||||
func get_weather() {
|
||||
result, _ := http.Get("https://api.caiyunapp.com/v2/TAkhjf8d1nlSlspN/113.960256,22.541454/realtime.json")
|
||||
body, _ := ioutil.ReadAll(result.Body)
|
||||
log.Println(string(body))
|
||||
data := Weather{}
|
||||
json.Unmarshal(body, &data)
|
||||
var icon string
|
||||
switch data.RESULT.SKYCON {
|
||||
case "CLEAR_DAY":
|
||||
icon = iconurl + "CLEAR_DAY.png"
|
||||
case "CLEAR_NIGHT":
|
||||
icon = iconurl + "CLEAR_NIGHT.png"
|
||||
case "PARTLY_CLOUDY_DAY":
|
||||
icon = iconurl + "PARTLY_CLOUDY_DAY.png"
|
||||
case "PARTLY_CLOUDY_NIGHT":
|
||||
icon = iconurl + "PARTLY_CLOUDY_NIGHT.png"
|
||||
case "CLOUDY":
|
||||
icon = iconurl + "icon/CLOUDY.png"
|
||||
case "RAIN":
|
||||
icon = iconurl + "RAIN.png"
|
||||
case "SNOW":
|
||||
icon = iconurl + "SNOW.png"
|
||||
case "WIND":
|
||||
icon = iconurl + "WIND.png"
|
||||
case "HAZE":
|
||||
icon = iconurl + "HAZE.png"
|
||||
}
|
||||
insert_db(data, icon)
|
||||
}
|
||||
|
||||
func insert_db(data Weather, icon string) {
|
||||
stmt, _ := db.Prepare(`INSERT INTO weather (
|
||||
skycon,
|
||||
icon_url,
|
||||
o3,
|
||||
co,
|
||||
so2,
|
||||
no2,
|
||||
temperature,
|
||||
humidity,
|
||||
pm25,
|
||||
pm10,
|
||||
cloudrate,
|
||||
aqi,
|
||||
dswrf,
|
||||
visibility,
|
||||
ultraviolet_desc,
|
||||
pres,
|
||||
precipitation_nearest_distance,
|
||||
precipitation_nearest_intensity,
|
||||
precipitation_local_intensity,
|
||||
comfort_desc,
|
||||
wind_direction,
|
||||
wind_speed) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)
|
||||
stmt.Exec(
|
||||
data.RESULT.SKYCON,
|
||||
icon,
|
||||
data.RESULT.O3,
|
||||
data.RESULT.CO,
|
||||
data.RESULT.SO2,
|
||||
data.RESULT.NO2,
|
||||
data.RESULT.TEMPERATURE,
|
||||
data.RESULT.HUMIDITY,
|
||||
data.RESULT.PM25,
|
||||
data.RESULT.PM10,
|
||||
data.RESULT.CLOUDRATE,
|
||||
data.RESULT.AQI,
|
||||
data.RESULT.DSWRF,
|
||||
data.RESULT.VISIBILITY,
|
||||
data.RESULT.ULTRAVIOLET.DESC,
|
||||
data.RESULT.PRES,
|
||||
data.RESULT.PERCIPITATION.NEAREST.DISTANCE,
|
||||
data.RESULT.PERCIPITATION.NEAREST.INTENSITY,
|
||||
data.RESULT.PERCIPITATION.LOCAL.INTENSITY,
|
||||
data.RESULT.COMFORT.DESC,
|
||||
data.RESULT.WIND.DIRECTION,
|
||||
data.RESULT.WIND.SPEED)
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Traffic struct {
|
||||
TRAFFIC uint16 `json:"traffic"`
|
||||
}
|
||||
|
||||
type Satisfaction struct {
|
||||
SATISFACTION float32 `json:"satisfaction"`
|
||||
}
|
||||
|
||||
type Conf struct {
|
||||
GATEWAY_INFO Gateway_info `json:"gateway_info"`
|
||||
DEVICES_LIST [][]string `json:"devices_list`
|
||||
SERIALPORTS_LIST map[string]Serialconf `json:"serialports_list"`
|
||||
RS485DEVICES map[string]Rs485devices `json:"rs485devices"`
|
||||
ICONURL string `json:"iconurl`
|
||||
WEBSOCKETURL []string `json:"websocketurl"`
|
||||
POST_TO_SERVER string `json:"post_to_server"`
|
||||
DEBUG bool `json:"debug"`
|
||||
}
|
||||
|
||||
type Gateway_info struct {
|
||||
ID string `json:"id"`
|
||||
VERSION string `json:"version"`
|
||||
LOCATION []float32 `json:"location"`
|
||||
UNITNAME string `json:"单位"`
|
||||
CONFIG []Config `json:"config"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
ID string `json:"id"`
|
||||
VERAION string `json:"version"`
|
||||
DATA [][]interface{} `json:"data"`
|
||||
}
|
||||
|
||||
type Rs485devices struct {
|
||||
VERSION string `json:"version"`
|
||||
NUM string `json:"num"`
|
||||
COMMAND [][]byte `json:"command"`
|
||||
}
|
||||
|
||||
type Serialconf struct {
|
||||
COM string `json:"com"`
|
||||
BAUDS int `json:"bauds"`
|
||||
SIZE uint16 `json:"size"`
|
||||
PARITY string `json:"parity"`
|
||||
STOPBITS int `json:"stopbits"`
|
||||
READTIMEOUT int `json:"readtimeout"`
|
||||
NOTE string `json:"note"`
|
||||
}
|
||||
|
||||
var conf Conf
|
||||
var DEVICEDATAS Devicedatas
|
||||
|
||||
var db, _ = sql.Open("sqlite3", "./db/gateway.db")
|
||||
|
||||
func init() {
|
||||
configfile, err := os.Open("conf/gateway.conf")
|
||||
check(err)
|
||||
defer configfile.Close()
|
||||
err = json.NewDecoder(configfile).Decode(&conf)
|
||||
check(err)
|
||||
var device Device
|
||||
|
||||
DEVICEDATAS.Lock()
|
||||
DEVICEDATAS.DATA = make(map[string]Device)
|
||||
for _, i := range conf.DEVICES_LIST {
|
||||
device.DATA = make(map[string]interface{})
|
||||
device.ID = i[0]
|
||||
device.VERSION = i[2]
|
||||
DEVICEDATAS.DATA[i[2]+"_"+i[3]] = device
|
||||
}
|
||||
DEVICEDATAS.Unlock()
|
||||
dbdata_init()
|
||||
}
|
||||
|
||||
var good, bad float32
|
||||
var traffic_data Traffic
|
||||
var satisfaction_data Satisfaction
|
||||
|
||||
func dbdata_init() {
|
||||
rows, err := db.Query("SELECT good, bad FROM satisfaction order by id DESC limit 1")
|
||||
if err != nil {
|
||||
good = 1
|
||||
bad = 0
|
||||
} else {
|
||||
rows.Next()
|
||||
rows.Scan(&good, &bad)
|
||||
rows.Close()
|
||||
}
|
||||
rows.Close()
|
||||
rows, err = db.Query("SELECT traffic FROM traffic t where datetime(t.create_time) > datetime('now','start of day','-1 day') order by id DESC limit 1 ")
|
||||
if err != nil {
|
||||
traffic_data.TRAFFIC = 0
|
||||
} else {
|
||||
rows.Next()
|
||||
rows.Scan(&traffic_data.TRAFFIC)
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func savedata_cron() {
|
||||
T := time.Now().Format("2006-01-02")
|
||||
stmt, err := db.Prepare("UPDATE satisfaction set good=?, bad=? ,create_time=? where id=(SELECT max(id) FROM satisfaction)")
|
||||
check(err)
|
||||
stmt.Exec(&good, &bad, &T)
|
||||
stmt, err = db.Prepare("UPDATE traffic set traffic=?, create_time=? where id=(SELECT max(id) FROM traffic)")
|
||||
check(err)
|
||||
stmt.Exec(&traffic_data.TRAFFIC, &T)
|
||||
}
|
||||
|
||||
func insertdata() {
|
||||
T := time.Now().Format("2006-01-02")
|
||||
stmt, _ := db.Prepare(`INSERT INTO traffic (traffic, create_time) values (?, ?)`)
|
||||
stmt.Exec(&traffic_data.TRAFFIC, &T)
|
||||
traffic_data.TRAFFIC = 0
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/robfig/cron"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
var err error
|
||||
|
||||
func main() {
|
||||
go gw_router()
|
||||
go serial_run()
|
||||
c := cron.New()
|
||||
c.AddFunc("0, *, *, *, *, *", func() {
|
||||
send_data(1001)
|
||||
})
|
||||
c.AddFunc("0, */10, *, *, *, *", savedata_cron)
|
||||
c.AddFunc("0, 0, 0, *, *, *", insertdata)
|
||||
c.AddFunc("0, 0, *, *, *, *", get_weather)
|
||||
c.Start()
|
||||
|
||||
select {}
|
||||
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,312 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var router = gin.Default()
|
||||
|
||||
func gw_router() {
|
||||
router.Use(cors.Default())
|
||||
v1 := router.Group("/api/v1")
|
||||
{
|
||||
v1.GET("/weather", gw_weather_api)
|
||||
v1.POST("/renliu", get_renliu_api)
|
||||
v1.POST("/feedback", get_pj_api)
|
||||
v1.GET("/totalWater", sb_api)
|
||||
v1.GET("/totalElectricity", db_api)
|
||||
v1.GET("/environmentDate", kq_api)
|
||||
v1.GET("/traffic", renliu_api)
|
||||
v1.GET("/stink", aq_api)
|
||||
v1.GET("/satisfaction", pj_api)
|
||||
v1.GET("/seat/:id", seat_api)
|
||||
}
|
||||
router.Run(":10086")
|
||||
}
|
||||
|
||||
type EventNotificationAlert struct {
|
||||
IPADDRESS string `xml:"ipAddress" json:"ipAddress"`
|
||||
PROTOCOLTYPE string `xml:"protocolType" json:"protocolType"`
|
||||
MACADDRESS string `xml:"macAddress" json:"macAddress"`
|
||||
CHANNELID uint16 `xml:"channelID" json:"channelID"`
|
||||
DATETIME string `xml:"dateTime" json:"dateTime"`
|
||||
ACTIVEPOSTCOUNT uint16 `xml:"activePostCount" json:"activePostCount"`
|
||||
EVENTTYPE string `xml:"eventType" json:"eventType"`
|
||||
EVENTSTATE string `xml:"eventState" json:"eventState"`
|
||||
EVENTDESCRIPTION string `xml:"eventDescription" json:"eventDescription"`
|
||||
CHANNELNAME string `xml:"channelName" json:"channelName"`
|
||||
PEOPLECOUNTING PeopleCounting `xml:"peopleCounting" json:"peopleCounting"`
|
||||
}
|
||||
|
||||
type PeopleCounting struct {
|
||||
STATISTICALMETHODS string `xml:"statisticalMethods" json:"statisticalMethods"`
|
||||
TIMERANGE Timerange `xml:"TimeRange" json:"TimeRange"`
|
||||
ENTER uint16 `xml:"enter" json:"enter"`
|
||||
EXIT uint16 `xml:"exit" json:"exit"`
|
||||
PASS uint16 `xml:"pass" json:"pass"`
|
||||
}
|
||||
|
||||
type Timerange struct {
|
||||
STARTTIME string `xml:"startTime" json:"startTime"`
|
||||
ENDTIME string `xml:"endTime" json:"endTime"`
|
||||
}
|
||||
|
||||
type FeedBack struct {
|
||||
FEEDBACK string `json:"feedback"`
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
var rl_data EventNotificationAlert
|
||||
|
||||
func get_renliu_api(c *gin.Context) {
|
||||
err := c.Bind(&rl_data)
|
||||
check(err)
|
||||
send_data(1004)
|
||||
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": rl_data})
|
||||
}
|
||||
|
||||
var pj_data FeedBack
|
||||
|
||||
func get_pj_api(c *gin.Context) {
|
||||
err = c.Bind(&pj_data)
|
||||
check(err)
|
||||
send_data(1006)
|
||||
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": pj_data})
|
||||
}
|
||||
|
||||
func sb_api(c *gin.Context) {
|
||||
DEVICEDATAS.RLock()
|
||||
var data = make(map[string]uint16)
|
||||
for _, i := range conf.DEVICES_LIST {
|
||||
if i[2] == "yunhorn_sb_c_v1" {
|
||||
if DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["totalWater"] != nil {
|
||||
data["totalWater"] = data["totalWater"] + DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["totalWater"].(uint16)
|
||||
}
|
||||
}
|
||||
}
|
||||
DEVICEDATAS.RUnlock()
|
||||
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data})
|
||||
}
|
||||
|
||||
func db_api(c *gin.Context) {
|
||||
DEVICEDATAS.RLock()
|
||||
var data = make(map[string]float32)
|
||||
for _, i := range conf.DEVICES_LIST {
|
||||
if i[2] == "yunhorn_db_c_v1" {
|
||||
if DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["totalElectric"] != nil {
|
||||
data["totalElectric"] = data["totalElectric"] + DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["totalElectric"].(float32)
|
||||
}
|
||||
}
|
||||
}
|
||||
DEVICEDATAS.RUnlock()
|
||||
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data})
|
||||
}
|
||||
|
||||
func kq_api(c *gin.Context) {
|
||||
DEVICEDATAS.RLock()
|
||||
var sum float32
|
||||
var toinitdata float32 = 0.0
|
||||
var data = make(map[string]interface{})
|
||||
for _, i := range conf.DEVICES_LIST {
|
||||
if i[2] == "yunhorn_kq_c_v1" {
|
||||
sum++
|
||||
for k, j := range DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA {
|
||||
if j != nil {
|
||||
data[k] = toinitdata
|
||||
data[k] = (data[k].(float32) + j.(float32)) / sum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DEVICEDATAS.RUnlock()
|
||||
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data})
|
||||
}
|
||||
|
||||
func aq_api(c *gin.Context) {
|
||||
DEVICEDATAS.RLock()
|
||||
var sum uint16
|
||||
var toinitdata uint16 = 0
|
||||
var data_buf = make(map[string]interface{})
|
||||
var data = make(map[string]interface{})
|
||||
for _, i := range conf.DEVICES_LIST {
|
||||
if i[2] == "yunhorn_aq_c_v1" {
|
||||
sum++
|
||||
if DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["氨气"] != nil {
|
||||
data_buf["氨气"] = toinitdata
|
||||
data_buf["氨气"] = (data_buf["氨气"].(uint16) + DEVICEDATAS.DATA["yunhorn_aq_c_v1_"+i[3]].DATA["氨气"].(uint16)) / sum
|
||||
}
|
||||
}
|
||||
}
|
||||
if data_buf["氨气"] == nil {
|
||||
data["stink"] = "无味"
|
||||
} else {
|
||||
if data_buf["氨气"].(uint16) <= 1 {
|
||||
data["stink"] = "无味"
|
||||
} else if data_buf["氨气"].(uint16) > 1 && data_buf["氨气"].(uint16) <= 10 {
|
||||
data["stink"] = "有味"
|
||||
} else if data_buf["氨气"].(uint16) > 10 && data_buf["氨气"].(uint16) <= 40 {
|
||||
data["stink"] = "恶臭"
|
||||
} else if data_buf["氨气"].(uint16) > 40 && data_buf["氨气"].(uint16) <= 100 {
|
||||
data["stink"] = "超级恶臭"
|
||||
}
|
||||
}
|
||||
DEVICEDATAS.RUnlock()
|
||||
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data})
|
||||
}
|
||||
|
||||
func renliu_api(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": traffic_data})
|
||||
}
|
||||
|
||||
func pj_api(c *gin.Context) {
|
||||
satisfaction_data.SATISFACTION = good / (good + bad)
|
||||
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": satisfaction_data})
|
||||
}
|
||||
|
||||
type Seat_data struct {
|
||||
POSITIONLIST []interface{} `json:"positionList"`
|
||||
HASPERSONLIST []interface{} `json:"hasPersonList"`
|
||||
EMPTYPOSITION uint16 `json:"emptyPosition"`
|
||||
OCCUPYPOSITION uint16 `json:"occupyPosition"`
|
||||
}
|
||||
|
||||
func seat_api(c *gin.Context) {
|
||||
DEVICEDATAS.RLock()
|
||||
type_id := c.Param("id")
|
||||
var data Seat_data
|
||||
var conf_data [][]interface{}
|
||||
for _, i := range conf.GATEWAY_INFO.CONFIG {
|
||||
arr := get_seat_device_data(i.ID)
|
||||
version, num := arr[0], arr[1]
|
||||
for k, j := range i.DATA {
|
||||
if DEVICEDATAS.DATA[version+"_"+num].DATA != nil {
|
||||
if DEVICEDATAS.DATA[version+"_"+num].DATA["data"+strconv.Itoa(k+1)] != nil {
|
||||
j = append(j, DEVICEDATAS.DATA[version+"_"+num].DATA["data"+strconv.Itoa(k+1)])
|
||||
}
|
||||
}
|
||||
conf_data = append(conf_data, j)
|
||||
}
|
||||
}
|
||||
switch type_id {
|
||||
case "1":
|
||||
data = scan_seat_from_confdata("男厕位", conf_data)
|
||||
case "2":
|
||||
data = scan_seat_from_confdata("男便池", conf_data)
|
||||
case "3":
|
||||
data = scan_seat_from_confdata("女厕位", conf_data)
|
||||
case "4":
|
||||
data = scan_seat_from_confdata("母婴", conf_data)
|
||||
case "5":
|
||||
data = scan_seat_from_confdata("残卫", conf_data)
|
||||
}
|
||||
DEVICEDATAS.RUnlock()
|
||||
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data})
|
||||
}
|
||||
|
||||
func get_seat_device_data(id string) []string {
|
||||
var data = make([]string, 2)
|
||||
for _, i := range conf.DEVICES_LIST {
|
||||
if id == i[0] {
|
||||
data[0], data[1] = i[2], i[3]
|
||||
break
|
||||
} else {
|
||||
data[0], data[1] = "null", "null"
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func scan_seat_from_confdata(T string, conf_data [][]interface{}) Seat_data {
|
||||
var data Seat_data
|
||||
for _, i := range conf_data {
|
||||
if i[0] == T {
|
||||
data.POSITIONLIST = append(data.POSITIONLIST, i[1])
|
||||
if len(i) < 3 {
|
||||
i = append(i, 0)
|
||||
}
|
||||
data.HASPERSONLIST = append(data.HASPERSONLIST, i[2])
|
||||
switch i[2] {
|
||||
case 0:
|
||||
data.EMPTYPOSITION++
|
||||
case 1:
|
||||
data.OCCUPYPOSITION++
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
type WEATHER struct {
|
||||
// gorm.Model
|
||||
SKYCON string `json:"skycon"`
|
||||
ICON_URL string `json:"icon_url"`
|
||||
O3 float32 `json:"o3"`
|
||||
CO float32 `json:"co"`
|
||||
SO2 float32 `json:"so2"`
|
||||
NO2 float32 `json:"no2"`
|
||||
TEMPERATURE float32 `json:"temperature"`
|
||||
HUMIDITY float32 `json:"humidity"`
|
||||
PM25 float32 `json:"pm25"`
|
||||
PM10 float32 `json:"pm10"`
|
||||
CLOUDRATE float32 `json:"cloudrate"`
|
||||
AQI float32 `json:"aqi"`
|
||||
DSWRF float32 `json:"dswrf"`
|
||||
VISIBILITY float32 `json:"visibility"`
|
||||
ULTRAVIOLET_DESC string `json:"ultraviolet_desc"`
|
||||
PRES float32 `json:"pres"`
|
||||
COMFORT_DESC string `json:"comfort_desc"`
|
||||
WIND_DIRECTION float32 `json:"wind_direction"`
|
||||
WIND_SPEED float32 `json:"wind_speed"`
|
||||
TEMPERATURE_INDOOR interface{} `json:"temperature_indoor"`
|
||||
HUMIDITY_INDOOR interface{} `json:"humidity_indoor"`
|
||||
}
|
||||
|
||||
func gw_weather_api(c *gin.Context) {
|
||||
DEVICEDATAS.RLock()
|
||||
rows, _ := db.Query("SELECT skycon, icon_url, o3, co, so2, no2, temperature, humidity, pm25, pm10, cloudrate, aqi, dswrf, visibility, ultraviolet_desc, pres, comfort_desc, wind_direction, wind_speed FROM weather order by id DESC limit 1")
|
||||
var data WEATHER
|
||||
rows.Next()
|
||||
rows.Scan(
|
||||
&data.SKYCON,
|
||||
&data.ICON_URL,
|
||||
&data.O3,
|
||||
&data.CO,
|
||||
&data.SO2,
|
||||
&data.NO2,
|
||||
&data.TEMPERATURE,
|
||||
&data.HUMIDITY,
|
||||
&data.PM25,
|
||||
&data.PM10,
|
||||
&data.CLOUDRATE,
|
||||
&data.AQI,
|
||||
&data.DSWRF,
|
||||
&data.VISIBILITY,
|
||||
&data.ULTRAVIOLET_DESC,
|
||||
&data.PRES,
|
||||
&data.COMFORT_DESC,
|
||||
&data.WIND_DIRECTION,
|
||||
&data.WIND_SPEED)
|
||||
rows.Close()
|
||||
var sum float32
|
||||
var toinitdata float32 = 0.0
|
||||
var data_buf = make(map[string]interface{})
|
||||
for _, i := range conf.DEVICES_LIST {
|
||||
if i[2] == "yunhorn_kq_c_v1" {
|
||||
sum++
|
||||
for k, j := range DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA {
|
||||
if j != nil {
|
||||
data_buf[k] = toinitdata
|
||||
data_buf[k] = (data_buf[k].(float32) + j.(float32)) / sum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
data.TEMPERATURE_INDOOR = data_buf["温度"]
|
||||
data.HUMIDITY_INDOOR = data_buf["湿度"]
|
||||
DEVICEDATAS.RUnlock()
|
||||
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data})
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/tarm/serial"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
func serial_run() {
|
||||
SERIAL_PORT := make(map[string]*serial.Port)
|
||||
ports_arr := make([]string, 0)
|
||||
port_arr := make([]string, 0)
|
||||
for _, i := range conf.DEVICES_LIST {
|
||||
ports_arr = append(ports_arr, i[1])
|
||||
}
|
||||
for i := 0; i < len(ports_arr); i++ {
|
||||
if (i > 0 && ports_arr[i-1] == ports_arr[i]) || len(ports_arr[i]) == 0 {
|
||||
continue
|
||||
}
|
||||
port_arr = append(port_arr, ports_arr[i])
|
||||
}
|
||||
for _, i := range port_arr {
|
||||
var PARITY serial.Parity
|
||||
switch conf.SERIALPORTS_LIST[i].PARITY {
|
||||
case "N":
|
||||
PARITY = 'N'
|
||||
case "E":
|
||||
PARITY = 'E'
|
||||
}
|
||||
SERIAL_PORT[i], err = serial.OpenPort(&serial.Config{
|
||||
Name: conf.SERIALPORTS_LIST[i].COM,
|
||||
Baud: conf.SERIALPORTS_LIST[i].BAUDS,
|
||||
Parity: PARITY,
|
||||
ReadTimeout: time.Second * time.Duration(conf.SERIALPORTS_LIST[i].READTIMEOUT)})
|
||||
check(err)
|
||||
defer SERIAL_PORT[i].Close()
|
||||
}
|
||||
if conf.DEBUG {
|
||||
log.Println(SERIAL_PORT)
|
||||
}
|
||||
for j, k := range SERIAL_PORT {
|
||||
var the_same_port_devices [][]string
|
||||
for _, i := range conf.DEVICES_LIST {
|
||||
if j == i[1] {
|
||||
the_same_port_devices = append(the_same_port_devices, i)
|
||||
}
|
||||
}
|
||||
go run_port_device(k, the_same_port_devices)
|
||||
}
|
||||
select {}
|
||||
}
|
||||
|
||||
func run_port_device(port *serial.Port, the_same_port_devices [][]string) {
|
||||
for {
|
||||
for _, i := range the_same_port_devices {
|
||||
switch i[2] {
|
||||
case "yunhorn_sb_c_v1":
|
||||
yunhorn_sb_c_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
||||
case "yunhorn_db_c_v1":
|
||||
yunhorn_db_c_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
||||
case "yunhorn_kq_c_v1":
|
||||
yunhorn_kq_c_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
||||
case "yunhorn_lhq_c_v1":
|
||||
yunhorn_lhq_c_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
||||
case "yunhorn_aq_c_v1":
|
||||
yunhorn_aq_c_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
||||
case "yunhorn_kgl_c8_v1":
|
||||
yunhorn_kgl_c8_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
||||
case "yunhorn_kgl_c16_v1":
|
||||
yunhorn_kgl_c16_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,348 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"github.com/tarm/serial"
|
||||
"log"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Devicedatas struct {
|
||||
sync.RWMutex
|
||||
DATA map[string]Device
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
sync.RWMutex
|
||||
ID string `json:"id"`
|
||||
VERSION string `json:"version"`
|
||||
ONLINE bool `json:"online"`
|
||||
DATA map[string]interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func yunhorn_sb_c_v1(s *serial.Port, device_id string, command [][]byte, num string) {
|
||||
_, err = s.Write([]byte(command[0]))
|
||||
check(err)
|
||||
if conf.DEBUG {
|
||||
log.Printf("命令:\t%x", []byte(command[0]))
|
||||
}
|
||||
buf := make([]byte, 128)
|
||||
b_buf := make([]byte, 0)
|
||||
var nn int
|
||||
for {
|
||||
n, err := s.Read(buf)
|
||||
nn = n + nn
|
||||
b_buf = append(b_buf, buf[:n]...)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if nn != 39 {
|
||||
return
|
||||
}
|
||||
data_buf := b_buf[17 : nn-20]
|
||||
|
||||
var device Device
|
||||
device.Lock()
|
||||
device.ID = device_id
|
||||
device.VERSION = "yunhorn_sb_c_v1"
|
||||
device.ONLINE = true
|
||||
device.DATA = make(map[string]interface{})
|
||||
device.DATA["totalWater"] = binary.BigEndian.Uint16(data_buf)
|
||||
device.Unlock()
|
||||
DEVICEDATAS.Lock()
|
||||
DEVICEDATAS.DATA["yunhorn_sb_c_v1_"+num] = device
|
||||
DEVICEDATAS.Unlock()
|
||||
|
||||
if conf.DEBUG {
|
||||
log.Println(device)
|
||||
}
|
||||
}
|
||||
|
||||
func yunhorn_db_c_v1(s *serial.Port, device_id string, command [][]byte, num string) {
|
||||
_, err = s.Write([]byte(command[0]))
|
||||
check(err)
|
||||
if conf.DEBUG {
|
||||
log.Printf("命令:\t%x", []byte(command[0]))
|
||||
}
|
||||
buf := make([]byte, 128)
|
||||
bb_buf := make([]byte, 0)
|
||||
var nn int
|
||||
for {
|
||||
n, err := s.Read(buf)
|
||||
nn = n + nn
|
||||
bb_buf = append(bb_buf, buf[:n]...)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if nn != 20 {
|
||||
return
|
||||
}
|
||||
data_buf := bb_buf[nn-6 : nn-2]
|
||||
for i, x := range data_buf {
|
||||
data_buf[i] = x - 0x33
|
||||
|
||||
}
|
||||
Len := len(data_buf) - 1
|
||||
for i, k := 0, Len; i < k; i++ {
|
||||
data_buf[i], data_buf[k] = data_buf[k], data_buf[i]
|
||||
k--
|
||||
}
|
||||
U8 := make([]byte, 0)
|
||||
for i := 0; i < 4; i++ {
|
||||
U8 = append(U8, data_buf[i]>>4)
|
||||
U8 = append(U8, data_buf[i]<<4>>4)
|
||||
}
|
||||
b_buf := make([]byte, 0)
|
||||
var db_data uint32
|
||||
b_buf = append([]byte{0, 0, 0}, U8[0])
|
||||
db_data = binary.BigEndian.Uint32(b_buf) * 10000000
|
||||
b_buf = append([]byte{0, 0, 0}, U8[1])
|
||||
db_data = db_data + binary.BigEndian.Uint32(b_buf)*1000000
|
||||
b_buf = append([]byte{0, 0, 0}, U8[2])
|
||||
db_data = db_data + binary.BigEndian.Uint32(b_buf)*100000
|
||||
b_buf = append([]byte{0, 0, 0}, U8[3])
|
||||
db_data = db_data + binary.BigEndian.Uint32(b_buf)*10000
|
||||
b_buf = append([]byte{0, 0, 0}, U8[4])
|
||||
db_data = db_data + binary.BigEndian.Uint32(b_buf)*1000
|
||||
b_buf = append([]byte{0, 0, 0}, U8[5])
|
||||
db_data = db_data + binary.BigEndian.Uint32(b_buf)*100
|
||||
b_buf = append([]byte{0, 0, 0}, U8[6])
|
||||
db_data = db_data + binary.BigEndian.Uint32(b_buf)*10
|
||||
b_buf = append([]byte{0, 0, 0}, U8[7])
|
||||
db_data = db_data + binary.BigEndian.Uint32(b_buf)
|
||||
|
||||
var device Device
|
||||
device.Lock()
|
||||
device.ID = device_id
|
||||
device.VERSION = "yunhorn_db_c_v1"
|
||||
device.ONLINE = true
|
||||
device.DATA = make(map[string]interface{})
|
||||
device.DATA["totalElectric"] = float32(db_data) / 100
|
||||
device.Unlock()
|
||||
DEVICEDATAS.Lock()
|
||||
DEVICEDATAS.DATA["yunhorn_db_c_v1_"+num] = device
|
||||
DEVICEDATAS.Unlock()
|
||||
|
||||
if conf.DEBUG {
|
||||
log.Println(device)
|
||||
}
|
||||
}
|
||||
|
||||
func yunhorn_kq_c_v1(s *serial.Port, device_id string, command [][]byte, num string) {
|
||||
_, err = s.Write([]byte(command[0]))
|
||||
check(err)
|
||||
if conf.DEBUG {
|
||||
log.Printf("命令:\t%x", []byte(command[0]))
|
||||
}
|
||||
buf := make([]byte, 128)
|
||||
b_buf := make([]byte, 0)
|
||||
var nn int
|
||||
for {
|
||||
n, err := s.Read(buf)
|
||||
nn = n + nn
|
||||
b_buf = append(b_buf, buf[:n]...)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if nn != 19 {
|
||||
return
|
||||
}
|
||||
data_buf := b_buf[3 : nn-2]
|
||||
|
||||
var device Device
|
||||
device.Lock()
|
||||
device.ID = device_id
|
||||
device.VERSION = "yunhorn_kq_c_v1"
|
||||
device.ONLINE = true
|
||||
device.DATA = make(map[string]interface{})
|
||||
device.DATA["二氧化碳"] = float32(binary.BigEndian.Uint16(data_buf[0:2]))
|
||||
device.DATA["TVOC"] = float32(binary.BigEndian.Uint16(data_buf[2:4])) / 10
|
||||
device.DATA["甲醛"] = float32(binary.BigEndian.Uint16(data_buf[4:6])) / 10
|
||||
device.DATA["pm2.5"] = float32(binary.BigEndian.Uint16(data_buf[6:8]))
|
||||
device.DATA["湿度"] = float32(binary.BigEndian.Uint16(data_buf[8:10])) / 10
|
||||
device.DATA["温度"] = float32(binary.BigEndian.Uint16(data_buf[10:13])) / 10
|
||||
device.DATA["PM10"] = float32(binary.BigEndian.Uint16(data_buf[12:14]))
|
||||
device.Unlock()
|
||||
DEVICEDATAS.Lock()
|
||||
DEVICEDATAS.DATA["yunhorn_kq_c_v1_"+num] = device
|
||||
DEVICEDATAS.Unlock()
|
||||
|
||||
if conf.DEBUG {
|
||||
log.Println(device)
|
||||
}
|
||||
}
|
||||
|
||||
func yunhorn_aq_c_v1(s *serial.Port, device_id string, command [][]byte, num string) {
|
||||
_, err = s.Write([]byte(command[0]))
|
||||
check(err)
|
||||
if conf.DEBUG {
|
||||
log.Printf("命令:\t%x", []byte(command[0]))
|
||||
}
|
||||
buf := make([]byte, 128)
|
||||
b_buf := make([]byte, 0)
|
||||
var nn int
|
||||
for {
|
||||
n, err := s.Read(buf)
|
||||
nn = n + nn
|
||||
b_buf = append(b_buf, buf[:n]...)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if nn != 7 {
|
||||
return
|
||||
}
|
||||
data_buf := b_buf[3 : nn-2]
|
||||
|
||||
var device Device
|
||||
device.Lock()
|
||||
device.ID = device_id
|
||||
device.VERSION = "yunhorn_aq_c_v1"
|
||||
device.ONLINE = true
|
||||
device.DATA = make(map[string]interface{})
|
||||
device.DATA["氨气"] = binary.BigEndian.Uint16(data_buf)
|
||||
device.Unlock()
|
||||
DEVICEDATAS.Lock()
|
||||
DEVICEDATAS.DATA["yunhorn_aq_c_v1_"+num] = device
|
||||
DEVICEDATAS.Unlock()
|
||||
|
||||
if conf.DEBUG {
|
||||
log.Println(device)
|
||||
}
|
||||
}
|
||||
|
||||
func yunhorn_lhq_c_v1(s *serial.Port, device_id string, command [][]byte, num string) {
|
||||
_, err = s.Write([]byte(command[0]))
|
||||
check(err)
|
||||
if conf.DEBUG {
|
||||
log.Printf("命令:\t%x", []byte(command[0]))
|
||||
}
|
||||
buf := make([]byte, 128)
|
||||
b_buf := make([]byte, 0)
|
||||
var nn int
|
||||
for {
|
||||
n, err := s.Read(buf)
|
||||
nn = n + nn
|
||||
b_buf = append(b_buf, buf[:n]...)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if nn != 7 {
|
||||
return
|
||||
}
|
||||
data_buf := b_buf[3 : nn-2]
|
||||
|
||||
var device Device
|
||||
device.Lock()
|
||||
device.ID = device_id
|
||||
device.VERSION = "yunhorn_lhq_c_v1"
|
||||
device.ONLINE = true
|
||||
device.DATA = make(map[string]interface{})
|
||||
device.DATA["硫化氢"] = binary.BigEndian.Uint16(data_buf)
|
||||
device.Unlock()
|
||||
DEVICEDATAS.Lock()
|
||||
DEVICEDATAS.DATA["yunhorn_lhq_c_v1_"+num] = device
|
||||
DEVICEDATAS.Unlock()
|
||||
|
||||
if conf.DEBUG {
|
||||
log.Println(device)
|
||||
}
|
||||
}
|
||||
|
||||
func yunhorn_kgl_c8_v1(s *serial.Port, device_id string, command [][]byte, num string) {
|
||||
buf := make([]byte, 128)
|
||||
b_buf := make([]byte, 0)
|
||||
for _, i := range command {
|
||||
_, err = s.Write([]byte(i))
|
||||
check(err)
|
||||
if conf.DEBUG {
|
||||
log.Printf("命令:\t%x", []byte(i))
|
||||
}
|
||||
_, err = s.Read(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
b_buf = append(b_buf, buf[3])
|
||||
}
|
||||
DEVICEDATAS.RLock()
|
||||
var olddata = DEVICEDATAS.DATA["yunhorn_kgl_c8_v1_"+num]
|
||||
DEVICEDATAS.RUnlock()
|
||||
var device Device
|
||||
device.Lock()
|
||||
device.ID = device_id
|
||||
device.VERSION = "yunhorn_kgl_c8_v1"
|
||||
device.ONLINE = true
|
||||
device.DATA = make(map[string]interface{})
|
||||
for i, k := range b_buf {
|
||||
device.DATA["data"+strconv.Itoa(i+1)] = binary.BigEndian.Uint16(append([]byte{0x00}, k))
|
||||
}
|
||||
device.Unlock()
|
||||
DEVICEDATAS.Lock()
|
||||
DEVICEDATAS.DATA["yunhorn_kgl_c8_v1_"+num] = device
|
||||
DEVICEDATAS.Unlock()
|
||||
for i, k := range device.DATA {
|
||||
if k != olddata.DATA[i] {
|
||||
send_data(1005, device)
|
||||
break
|
||||
}
|
||||
}
|
||||
if conf.DEBUG {
|
||||
log.Println(device)
|
||||
}
|
||||
}
|
||||
|
||||
func yunhorn_kgl_c16_v1(s *serial.Port, device_id string, command [][]byte, num string) {
|
||||
buf := make([]byte, 128)
|
||||
_, err = s.Write([]byte(command[0]))
|
||||
check(err)
|
||||
if conf.DEBUG {
|
||||
log.Printf("命令:\t%x", []byte(command[0]))
|
||||
}
|
||||
_, err = s.Read(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
b_buf := Bytes2Bits(buf[3:5])
|
||||
|
||||
DEVICEDATAS.RLock()
|
||||
var olddata = DEVICEDATAS.DATA["yunhorn_kgl_c16_v1_"+num]
|
||||
DEVICEDATAS.RUnlock()
|
||||
var device Device
|
||||
device.Lock()
|
||||
device.ID = device_id
|
||||
device.VERSION = "yunhorn_kgl_c16_v1"
|
||||
device.ONLINE = true
|
||||
device.DATA = make(map[string]interface{})
|
||||
for i, k := range b_buf {
|
||||
device.DATA["data_buf"+strconv.Itoa(i+1)] = k
|
||||
}
|
||||
device.Unlock()
|
||||
DEVICEDATAS.Lock()
|
||||
DEVICEDATAS.DATA["yunhorn_kgl_c16_v1_"+num] = device
|
||||
DEVICEDATAS.Unlock()
|
||||
for i, k := range device.DATA {
|
||||
if k != olddata.DATA[i] {
|
||||
send_data(1005, device)
|
||||
break
|
||||
}
|
||||
}
|
||||
if conf.DEBUG {
|
||||
log.Println(device)
|
||||
}
|
||||
}
|
||||
|
||||
func Bytes2Bits(data []byte) []uint16 {
|
||||
dst := make([]uint16, 0)
|
||||
for _, v := range data {
|
||||
for i := 0; i < 8; i++ {
|
||||
move := uint(i)
|
||||
dst = append(dst, uint16((v>>move)&1))
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
Loading…
Reference in New Issue