Jeffrey C. Ollie
2095a29c53
All checks were successful
continuous-integration/drone/push Build is passing
160 lines
5 KiB
Go
160 lines
5 KiB
Go
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"time"
|
|
|
|
"git.ocjtech.us/jeff/ble-sensors/lib/bluetooth"
|
|
cleargrass "git.ocjtech.us/jeff/ble-sensors/lib/cleargrass"
|
|
xiaomi_mijia "git.ocjtech.us/jeff/ble-sensors/lib/xiaomi/mijia"
|
|
xiaomi_scale "git.ocjtech.us/jeff/ble-sensors/lib/xiaomi/scale"
|
|
"github.com/go-ble/ble"
|
|
"github.com/go-ble/ble/linux"
|
|
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
|
|
influxdb2_api "github.com/influxdata/influxdb-client-go/v2/api"
|
|
"github.com/pkg/errors"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/viper"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// listenCmd represents the listen command
|
|
var listenCmd = &cobra.Command{
|
|
Use: "listen",
|
|
Short: "A brief description of your command",
|
|
Long: `A longer description that spans multiple lines and likely contains examples
|
|
and usage of using your command. For example:
|
|
|
|
Cobra is a CLI library for Go that empowers applications.
|
|
This application is a tool to generate the needed files
|
|
to quickly create a Cobra application.`,
|
|
Run: listen,
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(listenCmd)
|
|
|
|
// Here you will define your flags and configuration settings.
|
|
|
|
// Cobra supports Persistent Flags which will work for this command
|
|
// and all subcommands, e.g.:
|
|
// listenCmd.PersistentFlags().String("foo", "", "A help for foo")
|
|
|
|
// Cobra supports local flags which will only run when this command
|
|
// is called directly, e.g.:
|
|
|
|
}
|
|
|
|
var client influxdb2.Client
|
|
var writeAPI influxdb2_api.WriteAPI
|
|
|
|
func listen(cmd *cobra.Command, args []string) {
|
|
logger.Debug("starting up")
|
|
|
|
d, err := linux.NewDevice(ble.OptDeviceID(0))
|
|
if err != nil {
|
|
logger.Fatal("can't get new device",
|
|
zap.String("error", err.Error()))
|
|
}
|
|
|
|
serverURL := viper.GetString("influxdb2.server_url")
|
|
token := viper.GetString("influxdb2.token")
|
|
organization := viper.GetString("influxdb2.organization")
|
|
bucket := viper.GetString("influxdb2.bucket")
|
|
|
|
client = influxdb2.NewClientWithOptions(serverURL, token, influxdb2.DefaultOptions().SetBatchSize(20))
|
|
writeAPI = client.WriteAPI(organization, bucket)
|
|
|
|
ctx := ble.WithSigHandler(context.WithCancel(context.Background()))
|
|
chkErr(logger, d.Scan(ctx, true, advHandler))
|
|
|
|
writeAPI.Flush()
|
|
client.Close()
|
|
logger.Sync()
|
|
}
|
|
|
|
var tileUUID ble.UUID = []byte{0xed, 0xfe}
|
|
var nestUUID ble.UUID = []byte{0xaf, 0xfe}
|
|
var googleFastPairUUID ble.UUID = []byte{0x2c, 0xfe}
|
|
|
|
var detector, _ = os.Hostname()
|
|
|
|
func advHandler(advertisement ble.Advertisement) {
|
|
timestamp := time.Now()
|
|
description := bluetooth.GetDescription(advertisement.Addr())
|
|
|
|
point := influxdb2.NewPointWithMeasurement("rssi")
|
|
point.SetTime(timestamp)
|
|
if detector != "" {
|
|
point.AddTag("detector", detector)
|
|
}
|
|
point.AddTag("address", advertisement.Addr().String())
|
|
if description != "" {
|
|
point.AddTag("description", description)
|
|
}
|
|
point.AddTag("unit", "dBm")
|
|
point.AddField("value", advertisement.RSSI())
|
|
writeAPI.WritePoint(point)
|
|
|
|
logger.Debug("sending sensor reading",
|
|
zap.String("source", advertisement.Addr().String()),
|
|
zap.String("description", description),
|
|
zap.String("measurement", "rssi"),
|
|
zap.String("measurement_unit", "dBm"),
|
|
zap.Int("value", advertisement.RSSI()))
|
|
|
|
if len(advertisement.ServiceData()) > 0 {
|
|
for index, sd := range advertisement.ServiceData() {
|
|
switch {
|
|
case sd.UUID.Equal(xiaomi_scale.XiaomiScaleV1UUID):
|
|
xiaomi_scale.ParseXiaomiScaleV1(&writeAPI, logger, timestamp, detector, description, advertisement, index, sd)
|
|
|
|
case sd.UUID.Equal(xiaomi_scale.XiaomiScaleV2UUID):
|
|
xiaomi_scale.ParseXiaomiScaleV2(&writeAPI, logger, timestamp, detector, description, advertisement, index, sd)
|
|
|
|
case sd.UUID.Equal(xiaomi_mijia.XiaomiMijiaHTV1UUID):
|
|
xiaomi_mijia.ParseXiaomiMijiaSensorData(&writeAPI, logger, timestamp, detector, description, advertisement, index, sd)
|
|
|
|
case sd.UUID.Equal(cleargrass.CleargrassUUID):
|
|
cleargrass.ParseCleargrassSensorData(&writeAPI, logger, timestamp, detector, description, advertisement, index, sd)
|
|
|
|
case sd.UUID.Equal(tileUUID):
|
|
logger.Debug("ignoring tile ble advertisement",
|
|
zap.String("source", advertisement.Addr().String()),
|
|
zap.String("description", description),
|
|
zap.String("name", advertisement.LocalName()),
|
|
zap.String("uuid", sd.UUID.String()))
|
|
|
|
case sd.UUID.Equal(nestUUID):
|
|
logger.Debug("ignoring nest ble advertisement",
|
|
zap.String("source", advertisement.Addr().String()),
|
|
zap.String("description", description),
|
|
zap.String("name", advertisement.LocalName()),
|
|
zap.String("uuid", sd.UUID.String()))
|
|
|
|
default:
|
|
logger.Info("unknown service data type",
|
|
zap.String("source", advertisement.Addr().String()),
|
|
zap.String("description", description),
|
|
zap.String("name", advertisement.LocalName()),
|
|
zap.String("uuid", sd.UUID.String()),
|
|
zap.Binary("data", sd.Data))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func chkErr(logger *zap.Logger, err error) {
|
|
logger.Debug("chkErr")
|
|
switch errors.Cause(err) {
|
|
case nil:
|
|
case context.DeadlineExceeded:
|
|
logger.Debug("done")
|
|
case context.Canceled:
|
|
logger.Debug("canceled")
|
|
default:
|
|
logger.Fatal("error",
|
|
zap.String("error", err.Error()))
|
|
}
|
|
}
|