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" influxdb2_api "github.com/influxdata/influxdb-client-go/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 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())) } }