From b86186937bb3143ee670ce3d31195e1f61b1e9ff Mon Sep 17 00:00:00 2001 From: wyhwyhwyh <573805736@qq.com> Date: Fri, 4 Mar 2022 11:31:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=82=E5=AE=B6=E6=95=B0=E6=8D=AE=E6=8E=A5?= =?UTF-8?q?=E6=94=B6=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- go.mod | 2 +- main.go | 8 ++- mosquitto/config.go | 7 +++ mosquitto/handler.go | 23 ++++++++ mosquitto/mosquitto.go | 103 ++++++++++++++++++++++++++++++++++ service/ble-service.go | 122 +++++++++++++++++++++-------------------- 7 files changed, 207 insertions(+), 61 deletions(-) create mode 100644 mosquitto/config.go create mode 100644 mosquitto/handler.go create mode 100644 mosquitto/mosquitto.go diff --git a/.gitignore b/.gitignore index 778aa94..b95573c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ cok-ble .vscode *.sum *.yml -*.yaml \ No newline at end of file +*.yaml +logs \ No newline at end of file diff --git a/go.mod b/go.mod index b149bee..4c31db8 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,11 @@ module myschools.me/wyh/ble-april go 1.16 require ( + github.com/eclipse/paho.mqtt.golang v1.3.5 github.com/gin-gonic/gin v1.7.7 github.com/jonboulle/clockwork v0.2.2 // indirect github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible github.com/lestrrat-go/strftime v1.0.5 // indirect - github.com/paypal/gatt v0.0.0-20151011220935-4ae819d591cf github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 github.com/shirou/gopsutil v2.21.11+incompatible github.com/sirupsen/logrus v1.8.1 diff --git a/main.go b/main.go index fd41729..daf4304 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "github.com/sirupsen/logrus" "github.com/spf13/viper" "myschools.me/wyh/ble-april/gin" + "myschools.me/wyh/ble-april/mosquitto" "myschools.me/wyh/ble-april/service" ) @@ -22,9 +23,14 @@ func main() { "func": "main", }).Fatalf("%s", err.Error()) } + mosquitto.Init(&mosquitto.Config{ + Host: viper.GetString("mosquitto.host"), + Username: viper.GetString("mosquitto.username"), + Password: viper.GetString("mosquitto.password"), + }) //ble服务 - service.BleService() + service.BleDelivery() go service.BleMessagePush() go service.BleCacheClear() go service.Bletokeninit() diff --git a/mosquitto/config.go b/mosquitto/config.go new file mode 100644 index 0000000..d1039b8 --- /dev/null +++ b/mosquitto/config.go @@ -0,0 +1,7 @@ +package mosquitto + +type Config struct { + Host string + Username string + Password string +} diff --git a/mosquitto/handler.go b/mosquitto/handler.go new file mode 100644 index 0000000..c361105 --- /dev/null +++ b/mosquitto/handler.go @@ -0,0 +1,23 @@ +package mosquitto + +import ( + "fmt" + + MQTT "github.com/eclipse/paho.mqtt.golang" +) + +var connHandler MQTT.OnConnectHandler = func(client MQTT.Client) { + token := client.Subscribe("#", 0, serviceHandler) + if token.Wait() && token.Error() != nil { + fmt.Println(token.Error()) + } +} + +var connLostHandler MQTT.ConnectionLostHandler = func(client MQTT.Client, err error) { + fmt.Println(err.Error()) +} + +//具体业务订阅的处理,此处为示例 +var serviceHandler MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) { + fmt.Println(msg.Topic()) +} diff --git a/mosquitto/mosquitto.go b/mosquitto/mosquitto.go new file mode 100644 index 0000000..611da91 --- /dev/null +++ b/mosquitto/mosquitto.go @@ -0,0 +1,103 @@ +package mosquitto + +import ( + "encoding/json" + "errors" + + MQTT "github.com/eclipse/paho.mqtt.golang" +) + +var ( + clientSubscribe, clientDistribute MQTT.Client + config *Config +) + +func Init(c *Config) { + config = c + if config == nil { + config = &Config{ + Host: "tcp://127.0.0.1:1883", + } + } +} + +func Options() *MQTT.ClientOptions { + opts := MQTT.NewClientOptions() + opts.AddBroker(config.Host) + opts.Username = config.Username + opts.Password = config.Password + return opts +} + +func New() (MQTT.Client, error) { + if clientDistribute != nil { + return clientDistribute, nil + } + opts := Options() + clientDistribute = MQTT.NewClient(opts) + token := clientDistribute.Connect() + if token.Wait() && token.Error() != nil { + clientDistribute = nil + return nil, token.Error() + } + + return clientDistribute, nil +} + +//订阅,当事件为nil时可获取client +func Subscribe(connHandler MQTT.OnConnectHandler, lostHandler MQTT.ConnectionLostHandler) error { + if connHandler == nil { + return errors.New("handler is nil") + } + + opts := Options() + opts.OnConnect = connHandler //当连接成功后调用注册 + if lostHandler != nil { + opts.OnConnectionLost = lostHandler + } + + if clientSubscribe == nil { + clientSubscribe = MQTT.NewClient(opts) + } + + token := clientSubscribe.Connect() + if token.Wait() && token.Error() != nil { + clientSubscribe = nil + return token.Error() + } + + return nil +} + +//取消订阅 +func UnSubscribe(topic string) { + if clientSubscribe == nil { + return + } + c := clientSubscribe + c.Unsubscribe(topic) + c.Disconnect(250) +} + +//分发 +func Distribute(topic *string, qos int, retained bool, payload *[]byte) error { + c, err := New() + if err != nil { + return err + } + + token := c.Publish(*topic, byte(qos), retained, *payload) + if token.Wait() && token.Error() != nil { + return token.Error() + } + return nil +} + +//分发Object +func DistributeObject(topic *string, qos int, retained bool, obj interface{}) error { + payload, err := json.Marshal(obj) + if err != nil { + return err + } + return Distribute(topic, qos, retained, &payload) +} diff --git a/service/ble-service.go b/service/ble-service.go index 6de48e9..927fc5c 100644 --- a/service/ble-service.go +++ b/service/ble-service.go @@ -1,24 +1,23 @@ package service import ( - "encoding/binary" + "encoding/hex" "encoding/json" "errors" "fmt" "io/ioutil" - "log" "net/http" "strings" "time" - "github.com/paypal/gatt" - "github.com/paypal/gatt/examples/option" + MQTT "github.com/eclipse/paho.mqtt.golang" "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/disk" "github.com/shirou/gopsutil/mem" "github.com/sirupsen/logrus" "github.com/spf13/viper" "github.com/vmihailenco/msgpack" + "myschools.me/wyh/ble-april/mosquitto" ) var m map[string]*IBeancon @@ -94,47 +93,46 @@ func Bletokeninit() { } //蓝牙接收服务 -func BleService() { - go func() { - dev, err := gatt.NewDevice(option.DefaultClientOptions...) - if err != nil { - log.Fatalf("Failed to open device, err:%s\n", err) + +var connHandler MQTT.OnConnectHandler = func(client MQTT.Client) { + token := client.Subscribe("gw/april", 0, serviceHandler) + if token.Wait() && token.Error() != nil { + fmt.Println(token.Error()) + } +} + +var connLostHandler MQTT.ConnectionLostHandler = func(client MQTT.Client, err error) { + fmt.Println(err.Error()) +} + +//具体业务订阅的处理,此处为示例 +var serviceHandler MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) { + out1 := make(map[string]interface{}, 0) + if err := msgpack.Unmarshal(msg.Payload(), &out1); err != nil { + logrus.WithFields(logrus.Fields{ + "func": "NewiBeacon", + }).Warnf("%s", err.Error()) + return + } + // 解析out1.device + bles := BleDecode(out1["devices"].([]interface{})) + for _, d := range bles { + chn <- &IBeancon{ + DeviceID: fmt.Sprintf("%s:%s:%s:%s:%s:%s", d.Mac[0:2], d.Mac[2:4], d.Mac[4:6], d.Mac[6:8], d.Mac[8:10], d.Mac[10:12]), + HappenTime: time.Now(), + Updated: time.Now().Unix(), } - dev.Handle( - gatt.PeripheralDiscovered(onPerhipheralDiscovered), - ) - dev.Init(onStateChanged) - }() -} - -func onStateChanged(device gatt.Device, s gatt.State) { - switch s { - case gatt.StatePoweredOn: - device.Scan([]gatt.UUID{}, true) - return - default: - device.StopScanning() } } -func onPerhipheralDiscovered(p gatt.Peripheral, a *gatt.Advertisement, rssi int) { - //小于设定阈值不处理 - if rssi < viper.GetInt("option.rssi") { - return - } - // 实例化蓝牙数据 - b, err := NewiBeacon(a.ManufacturerData, p.ID()) - if err != nil { - return - } - if beacon := m[b.DeviceID]; beacon != nil { - beacon.Updated = b.HappenTime.Unix() - m[b.DeviceID] = beacon +func BleDelivery() { + if err := mosquitto.Subscribe(connHandler, connLostHandler); err != nil { + logrus.WithFields(logrus.Fields{ + "func": "BleDelivery", + }).Warnf("%s", err.Error()) return } - // 更新持续时长和更新时间 - chn <- b } // 取出数据进行处理 @@ -293,30 +291,23 @@ type BeaconAprilBag struct { type BeaconApril struct { AdvType string Mac string - Rssi int + Rssi string AdvertisementData string } -func NewiBeacon(data []byte, mac string) (*IBeancon, error) { - out1 := &BeaconAprilBag{} - if err := msgpack.Unmarshal(data, &out1); err != nil { - logrus.WithFields(logrus.Fields{ - "func": "NewiBeacon", - }).Warnf("%s", err.Error()) - return nil, err - } - // 解析out1.device - // bytes.Split() +// func NewiBeacon(data []byte, mac string) (*IBeancon, error) { - if len(data) < 25 || binary.BigEndian.Uint32(data) != 0x4c000215 { - return nil, errors.New("not an iBeacon") - } - beacon := new(IBeancon) - beacon.DeviceID = mac - beacon.HappenTime = time.Now() - beacon.Updated = time.Now().Unix() - return beacon, nil -} +// // bytes.Split() + +// if len(data) < 25 || binary.BigEndian.Uint32(data) != 0x4c000215 { +// return nil, errors.New("not an iBeacon") +// } +// beacon := new(IBeancon) +// beacon.DeviceID = blespril.Mac +// beacon.HappenTime = time.Now() +// beacon.Updated = time.Now().Unix() +// return beacon, nil +// } // 清除缓存 func BleCacheClear() { @@ -335,3 +326,18 @@ func BleCacheClear() { time.Sleep(time.Duration(t/5) * time.Second) } } + +// 蓝牙解密 +func BleDecode(data []interface{}) []*BeaconApril { + bles := make([]*BeaconApril, 0) + for _, val := range data { + vals := strings.ToUpper(hex.EncodeToString(val.([]byte))) + bles = append(bles, &BeaconApril{ + AdvType: vals[0:2], + Mac: vals[2:14], + Rssi: vals[14:16], + AdvertisementData: vals[16:], + }) + } + return bles +}