ble-sensors/lib/cleargrass/sensor.go

121 lines
3.7 KiB
Go

package cleargrass
import (
"encoding/binary"
"encoding/hex"
"time"
"github.com/go-ble/ble"
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
influxdb2_api "github.com/influxdata/influxdb-client-go/v2/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 := uint8(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.Uint8("value", battery))
default:
logger.Warn("unknown event type",
zap.Uint8("event_type", eventType),
zap.String("event_data", hex.Dump(eventData)))
}
}
}