/
ruuvi.go
98 lines (75 loc) · 3.33 KB
/
ruuvi.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package ruuvi
import (
"encoding/binary"
"fmt"
"github.com/LassiHeikkila/go-ruuvi/internal/pkg/rawv1"
"github.com/LassiHeikkila/go-ruuvi/internal/pkg/rawv2"
)
const RUUVI_INNOVATIONS_LTD_TAG = 0x0499
// AdvertisementData is an interface abstracting away raw data from Ruuvitag BLE advertisements
//
// It provides methods to easily get the interesting values without having to manually parse byte arrays
type AdvertisementData interface {
// DataFormat returns format of underlying data
DataFormat() int8
// Temperature returns measured temperature in degrees Celsius
Temperature() (float64, error)
// Humidity returns measured humidity as percentage
Humidity() (float64, error)
// Pressure returns measured atmospheric pressure with unit Pa (pascal)
Pressure() (int, error)
// AccelerationX returns the acceleration in X axis with unit G, if supported by data format
AccelerationX() (float64, error)
// AccelerationY returns the acceleration in Y axis with unit G, if supported by data format
AccelerationY() (float64, error)
// AccelerationZ returns the acceleration in Z axis with unit G, if supported by data format
AccelerationZ() (float64, error)
// BatteryVoltage returns battery voltage with unit V (volt), if supported by data format
BatteryVoltage() (float64, error)
// TransmissionPower returns transmission power with unit dBm, if supported by data format
TransmissionPower() (float64, error)
// MovementCounter returns number of movements detected by accelerometer, if supported by data format
MovementCounter() (int, error)
// MeasurementSequenceNumber returns measurement sequence number, if supported by data format
MeasurementSequenceNumber() (int, error)
// MACAddress returns MAC address of broadcasting ruuvitag, if supported by data format
MACAddress() ([]byte, error)
// RawData returns the raw bytes. Make sure to copy the data, or it may be overwritten by the next broadcast.
RawData() []byte
// Copy copies the raw bytes internally so the AdvertisementData object is safe to use for a longer time.
// Without Copy(), incoming BLE packets can overwrite the bytes
Copy()
// MarshalJSON outputs available data as JSON
MarshalJSON() ([]byte, error)
}
// ProcessAdvertisement processes the given bytes and returns AdvertisementData or error
// error will be nil if AdvertisementData is valid (given data was valid and of a supported format)
// error will be non-nil if given data was invalid or of an unsupported format.
func ProcessAdvertisement(data []byte) (AdvertisementData, error) {
if !IsAdvertisementFromRuuviTag(data) {
return nil, newUnsupportedData("Data is not from Ruuvi Innovations Ltd product")
}
switch data[2] {
case 0x3:
return rawv1.NewDataRAWv1(data[2:])
case 0x5:
return rawv2.NewDataRAWv2(data[2:])
}
return nil, newUnsupportedData("Package does not support this data format (yet)")
}
func IsAdvertisementFromRuuviTag(data []byte) bool {
if len(data) < 2 {
return false
}
return binary.LittleEndian.Uint16(data[0:2]) == RUUVI_INNOVATIONS_LTD_TAG
}
// UnsupportedData is an error returned when package does not know how to handle given data
type UnsupportedData struct {
description string
}
func newUnsupportedData(desc string) *UnsupportedData {
return &UnsupportedData{description: desc}
}
func (ud *UnsupportedData) Error() string {
return fmt.Sprint("Unsupported data:", ud.description)
}