mirror of https://github.com/cmur2/miflorad.git
126 lines
3.7 KiB
Go
126 lines
3.7 KiB
Go
package common
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"math"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/currantlabs/gatt"
|
|
)
|
|
|
|
type VersionBatteryResponse struct {
|
|
FirmwareVersion string // as "x.y.z"
|
|
BatteryLevel uint8 // in percent 0-100
|
|
}
|
|
|
|
type SensorDataResponse struct {
|
|
Temperature float64 // in degree C
|
|
Brightness uint32 // in lux
|
|
Moisture uint8 // in percent 0-100
|
|
Conductivity uint16 // in µS/cm
|
|
}
|
|
|
|
func MifloraGetModeChangeData() []byte {
|
|
return []byte{0xa0, 0x1f}
|
|
}
|
|
|
|
var MifloraServiceUUID = gatt.MustParseUUID("00001204-0000-1000-8000-00805f9b34fb")
|
|
var MifloraCharModeChangeUUID = gatt.MustParseUUID("00001a00-0000-1000-8000-00805f9b34fb")
|
|
var MifloraCharReadSensorDataUUID = gatt.MustParseUUID("00001a01-0000-1000-8000-00805f9b34fb")
|
|
var MifloraCharVersionBatteryUUID = gatt.MustParseUUID("00001a02-0000-1000-8000-00805f9b34fb")
|
|
|
|
func FindServiceByUUID(services []*gatt.Service, u gatt.UUID) *gatt.Service {
|
|
for _, service := range services {
|
|
if service.UUID().Equal(u) {
|
|
return service
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func FindCharacteristicByUUID(characteristics []*gatt.Characteristic, u gatt.UUID) *gatt.Characteristic {
|
|
for _, characteristic := range characteristics {
|
|
if characteristic.UUID().Equal(u) {
|
|
return characteristic
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func MifloraRequestVersionBattery(p gatt.Peripheral) (VersionBatteryResponse, error) {
|
|
mifloraService := FindServiceByUUID(p.Services(), MifloraServiceUUID)
|
|
if mifloraService == nil {
|
|
return VersionBatteryResponse{}, errors.New("Failed to get the miflora service")
|
|
}
|
|
|
|
mifloraVersionBatteryChar := FindCharacteristicByUUID(mifloraService.Characteristics(), MifloraCharVersionBatteryUUID)
|
|
if mifloraVersionBatteryChar == nil {
|
|
return VersionBatteryResponse{}, errors.New("Failed to get the version battery characteristic")
|
|
}
|
|
|
|
bytes, err := p.ReadCharacteristic(mifloraVersionBatteryChar)
|
|
if err != nil {
|
|
return VersionBatteryResponse{}, err
|
|
}
|
|
|
|
return VersionBatteryResponse{string(bytes[2:]), uint8(bytes[0])}, nil
|
|
}
|
|
|
|
func MifloraRequestModeChange(p gatt.Peripheral) error {
|
|
mifloraService := FindServiceByUUID(p.Services(), MifloraServiceUUID)
|
|
if mifloraService == nil {
|
|
return errors.New("Failed to get the miflora service")
|
|
}
|
|
|
|
mifloraModeChangeChar := FindCharacteristicByUUID(mifloraService.Characteristics(), MifloraCharModeChangeUUID)
|
|
if mifloraModeChangeChar == nil {
|
|
return errors.New("Failed to discover the mode change characteristic")
|
|
}
|
|
|
|
err := p.WriteCharacteristic(mifloraModeChangeChar, MifloraGetModeChangeData(), false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func MifloraRequstSensorData(p gatt.Peripheral) (SensorDataResponse, error) {
|
|
mifloraService := FindServiceByUUID(p.Services(), MifloraServiceUUID)
|
|
if mifloraService == nil {
|
|
return SensorDataResponse{}, errors.New("Failed to get the miflora service")
|
|
}
|
|
|
|
mifloraSensorDataChar := FindCharacteristicByUUID(mifloraService.Characteristics(), MifloraCharReadSensorDataUUID)
|
|
if mifloraSensorDataChar == nil {
|
|
return SensorDataResponse{}, errors.New("Failed to discover the sensor data characteristic")
|
|
}
|
|
|
|
bytes, err := p.ReadCharacteristic(mifloraSensorDataChar)
|
|
if err != nil {
|
|
return SensorDataResponse{}, err
|
|
}
|
|
|
|
return SensorDataResponse{
|
|
Temperature: float64(binary.LittleEndian.Uint16(bytes[0:2])) / 10.0,
|
|
Brightness: binary.LittleEndian.Uint32(bytes[3:7]),
|
|
Moisture: uint8(bytes[7]),
|
|
Conductivity: binary.LittleEndian.Uint16(bytes[8:10]),
|
|
}, nil
|
|
}
|
|
|
|
func (res VersionBatteryResponse) NumericFirmwareVersion() int {
|
|
// turns "2.3.4" into 20304
|
|
version := 0
|
|
parts := strings.Split(res.FirmwareVersion, ".")
|
|
for i, part := range parts {
|
|
partNumber, err := strconv.Atoi(part)
|
|
if err != nil {
|
|
version += int(math.Pow10((len(parts)-(i+1))*2)) * partNumber
|
|
}
|
|
}
|
|
return version
|
|
}
|