ble-sensors/lib/xiaomi/scale/scale_v2.go
2020-08-08 19:00:41 -05:00

126 lines
3.5 KiB
Go

package scale
import (
"bytes"
"encoding/binary"
"fmt"
"log"
"os"
"sync"
"time"
"github.com/currantlabs/ble"
influxdb2 "github.com/influxdata/influxdb-client-go"
influxdb2_api "github.com/influxdata/influxdb-client-go/api"
)
// XiaomiScaleV2UUID is BLE UUID for Xiaomi Scale V2
var XiaomiScaleV2UUID ble.UUID = []byte{0x1b, 0x18}
// ParseXiaomiScaleV2 parses V2 scale service data
func ParseXiaomiScaleV2(mux *sync.Mutex, writeAPI *influxdb2_api.WriteAPI, advertisement ble.Advertisement, index int, sd ble.ServiceData) {
timestamp := time.Now()
var scaleData struct {
RawUnit uint8
ControlByte uint8
Year uint16
Month uint8
Day uint8
Hour uint8
Minute uint8
Second uint8
Impedance uint16
RawWeight uint16
}
err := binary.Read(bytes.NewBuffer(sd.Data), binary.LittleEndian, &scaleData)
if err != nil {
panic(err)
}
isStabilized := (scaleData.ControlByte & (1 << 5)) != 0
hasImpedance := (scaleData.ControlByte & (1 << 1)) != 0
var originalUnit string
var weight float64
switch scaleData.RawUnit {
case 3:
originalUnit = "lbs"
weight = float64(scaleData.RawWeight) / 100.0 * 0.453592
case 2:
originalUnit = "kg"
weight = float64(scaleData.RawWeight) / 200.0
default:
originalUnit = "unknown"
weight = float64(scaleData.RawWeight)
}
if isStabilized {
loc, err := time.LoadLocation("Local")
if err != nil {
log.Fatal(err)
}
scaleTimestamp := time.Date(
int(scaleData.Year),
time.Month(scaleData.Month),
int(scaleData.Day),
int(scaleData.Hour),
int(scaleData.Minute),
int(scaleData.Second),
0,
loc)
difference := timestamp.Sub(scaleTimestamp)
point := influxdb2.NewPointWithMeasurement("sensor")
point.SetTime(scaleTimestamp)
hostname, _ := os.Hostname()
if hostname != "" {
point.AddTag("detector", hostname)
}
point.AddTag("address", advertisement.Address().String())
point.AddTag("weight_unit", "kg")
point.AddTag("original_weight_unit", originalUnit)
point.AddField("rssi", advertisement.RSSI())
point.AddField("weight", weight)
if hasImpedance {
point.AddField("impedance", scaleData.Impedance)
}
(*writeAPI).WritePoint(point)
mux.Lock()
fmt.Printf("*******************************************\n")
fmt.Printf("Xiaomi V2 Scale\n")
fmt.Printf("[%s] %3d:\n", advertisement.Address(), advertisement.RSSI())
if len(advertisement.LocalName()) > 0 {
fmt.Printf(" Name: %s\n", advertisement.LocalName())
}
if len(advertisement.Services()) > 0 {
fmt.Printf(" Svcs: %v\n", advertisement.Services())
}
if len(advertisement.ManufacturerData()) > 0 {
fmt.Printf(" MD: %v\n", advertisement.ManufacturerData())
}
fmt.Printf(" rawUnit: %d\n", scaleData.RawUnit)
fmt.Printf(" Control byte: %d %b\n", scaleData.ControlByte, scaleData.ControlByte)
fmt.Printf(" Control byte X: %d\n", scaleData.ControlByte&^(1<<5)&^(1<<1))
fmt.Printf(" Is stabilized: %v\n", isStabilized)
fmt.Printf(" Has impedance: %v\n", hasImpedance)
fmt.Printf(" Year: %d\n", scaleData.Year)
fmt.Printf(" Month: %d\n", scaleData.Month)
fmt.Printf(" Day: %v\n", scaleData.Day)
fmt.Printf(" Hour: %d\n", scaleData.Hour)
fmt.Printf(" Minute: %d\n", scaleData.Minute)
fmt.Printf(" Second: %d\n", scaleData.Second)
fmt.Printf(" Measurement taken %s ago\n", difference)
fmt.Printf(" Impedance: %d\n", scaleData.Impedance)
fmt.Printf(" Raw weight: %d\n", scaleData.RawWeight)
fmt.Printf(" Weight: %f %s\n", weight, originalUnit)
fmt.Printf("*******************************************\n")
mux.Unlock()
}
}