package cleargrass import ( "encoding/binary" "encoding/hex" "time" "github.com/go-ble/ble" influxdb2 "github.com/influxdata/influxdb-client-go" influxdb2_api "github.com/influxdata/influxdb-client-go/api" "go.uber.org/zap" ) // https://github.com/alexvenom/XiaomiCleargrassInkDislpay/blob/master/XiaomiClearGrassInk.js // CleargrassUUID is the Bluetooth UUID for Cleargrass BLE sensor data var CleargrassUUID ble.UUID = []byte{0xcd, 0xfd} // ParseCleargrassSensorData . func ParseCleargrassSensorData(writeAPI *influxdb2_api.WriteAPI, logger *zap.Logger, timestamp time.Time, detector string, description string, advertisement ble.Advertisement, index int, sd ble.ServiceData) { logger.Debug("cleargrass", zap.String("event_data", hex.Dump(sd.Data)), zap.Int("length", len(sd.Data))) for eventOffset := 8; eventOffset < len(sd.Data)-2; { eventType := sd.Data[eventOffset] eventLength := int(sd.Data[eventOffset+1]) if eventOffset+eventLength > len(sd.Data) { logger.Warn("event length exceeds data length") return } eventData := sd.Data[eventOffset+2 : eventOffset+2+eventLength] eventOffset = eventOffset + 2 + eventLength switch eventType { case 0x01: if eventLength != 4 { logger.Warn("temperature/humidity event length should be 4", zap.String("event_data", hex.Dump(eventData))) continue } temperature := float64(binary.LittleEndian.Uint16(eventData[0:2])) / 10 point := influxdb2.NewPointWithMeasurement("temperature") point.SetTime(timestamp) if detector != "" { point.AddTag("detector", detector) } point.AddTag("address", advertisement.Addr().String()) if description != "" { point.AddTag("description", description) } point.AddTag("unit", "°C") point.AddField("value", temperature) (*writeAPI).WritePoint(point) logger.Debug("sending sensor reading", zap.String("source", advertisement.Addr().String()), zap.String("description", description), zap.String("measurement", "temperature"), zap.String("measurement_unit", "°C"), zap.Float64("value", temperature)) humidity := float64(binary.LittleEndian.Uint16(eventData[2:4])) / 10 point = influxdb2.NewPointWithMeasurement("humidity") point.SetTime(timestamp) if detector != "" { point.AddTag("detector", detector) } point.AddTag("address", advertisement.Addr().String()) if description != "" { point.AddTag("description", description) } point.AddTag("unit", "%") point.AddField("value", humidity) (*writeAPI).WritePoint(point) logger.Debug("sending sensor reading", zap.String("source", advertisement.Addr().String()), zap.String("description", description), zap.String("measurement", "humidity"), zap.String("measurement_unit", "%"), zap.Float64("value", humidity)) case 0x02: if eventLength != 1 { logger.Warn("battery event length should be 1") continue } battery := int(eventData[0]) point := influxdb2.NewPointWithMeasurement("battery") point.SetTime(timestamp) if detector != "" { point.AddTag("detector", detector) } point.AddTag("address", advertisement.Addr().String()) if description != "" { point.AddTag("description", description) } point.AddTag("unit", "%") point.AddField("value", battery) (*writeAPI).WritePoint(point) logger.Debug("sending sensor reading", zap.String("source", advertisement.Addr().String()), zap.String("description", description), zap.String("measurement", "battery"), zap.String("measurement_unit", "%"), zap.Int("value", battery)) default: logger.Warn("unknown event type", zap.Uint8("event_type", eventType), zap.String("event_data", hex.Dump(eventData))) } } }