This commit is contained in:
kk 2019-01-31 09:59:26 +08:00
commit 598ec1c8d9
11 changed files with 1583 additions and 0 deletions

0
README.md Normal file
View File

252
conf/README.md Normal file
View File

@ -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有线通讯zigbeelora未集成
提供api详见api说明
数据解析发送目前4种数据格式code1001code1004code1005code1006
code1001: 5分钟一次 (设备列表里的所有设备的数据)
code1004: 不定时,取决于客流摄像机
code1005: 不定时,当设备数据变化时发送该设备数据
code1006: 不定时,当有人评价时,发送评价设备的数据给服务器

170
conf/gateway.conf Normal file
View File

@ -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
}

BIN
db/gateway.db Normal file

Binary file not shown.

115
do_send_data.go Normal file
View File

@ -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))
}
}

155
get_weather.go Normal file
View File

@ -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)
}

125
loadconfig.go Normal file
View File

@ -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
}

32
main.go Normal file
View File

@ -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)
}
}

312
router.go Normal file
View File

@ -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})
}

74
serial_init.go Normal file
View File

@ -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)
}
}
}
}

348
worker.go Normal file
View File

@ -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
}