-
Notifications
You must be signed in to change notification settings - Fork 110
/
sensor.go
148 lines (128 loc) · 4.48 KB
/
sensor.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Package sensor defines an abstract sensing device that can provide measurement readings.
package sensor
import (
"context"
"sync"
"github.com/edaniels/golog"
pb "go.viam.com/api/component/sensor/v1"
viamutils "go.viam.com/utils"
"go.viam.com/utils/rpc"
"go.viam.com/rdk/components/generic"
"go.viam.com/rdk/data"
"go.viam.com/rdk/registry"
"go.viam.com/rdk/resource"
"go.viam.com/rdk/robot"
"go.viam.com/rdk/subtype"
"go.viam.com/rdk/utils"
)
func init() {
registry.RegisterResourceSubtype(Subtype, registry.ResourceSubtype{
Reconfigurable: WrapWithReconfigurable,
RegisterRPCService: func(ctx context.Context, rpcServer rpc.Server, subtypeSvc subtype.Service) error {
return rpcServer.RegisterServiceServer(
ctx,
&pb.SensorService_ServiceDesc,
NewServer(subtypeSvc),
pb.RegisterSensorServiceHandlerFromEndpoint,
)
},
RPCServiceDesc: &pb.SensorService_ServiceDesc,
RPCClient: func(ctx context.Context, conn rpc.ClientConn, name string, logger golog.Logger) interface{} {
return NewClientFromConn(ctx, conn, name, logger)
},
})
data.RegisterCollector(data.MethodMetadata{
Subtype: Subtype,
MethodName: readings.String(),
}, newSensorCollector)
}
// SubtypeName is a constant that identifies the component resource subtype string "Sensor".
const SubtypeName = resource.SubtypeName("sensor")
// Subtype is a constant that identifies the component resource subtype.
var Subtype = resource.NewSubtype(
resource.ResourceNamespaceRDK,
resource.ResourceTypeComponent,
SubtypeName,
)
// Named is a helper for getting the named Sensor's typed resource name.
func Named(name string) resource.Name {
return resource.NameFromSubtype(Subtype, name)
}
// A Sensor represents a general purpose sensors that can give arbitrary readings
// of some thing that it is sensing.
type Sensor interface {
// Readings return data specific to the type of sensor and can be of any type.
Readings(ctx context.Context, extra map[string]interface{}) (map[string]interface{}, error)
generic.Generic
}
var (
_ = Sensor(&reconfigurableSensor{})
_ = resource.Reconfigurable(&reconfigurableSensor{})
_ = viamutils.ContextCloser(&reconfigurableSensor{})
)
// NewUnimplementedInterfaceError is used when there is a failed interface check.
func NewUnimplementedInterfaceError(actual interface{}) error {
return utils.NewUnimplementedInterfaceError((*Sensor)(nil), actual)
}
// FromRobot is a helper for getting the named Sensor from the given Robot.
func FromRobot(r robot.Robot, name string) (Sensor, error) {
return robot.ResourceFromRobot[Sensor](r, Named(name))
}
// NamesFromRobot is a helper for getting all sensor names from the given Robot.
func NamesFromRobot(r robot.Robot) []string {
return robot.NamesBySubtype(r, Subtype)
}
type reconfigurableSensor struct {
mu sync.RWMutex
name resource.Name
actual Sensor
}
func (r *reconfigurableSensor) Name() resource.Name {
return r.name
}
func (r *reconfigurableSensor) Close(ctx context.Context) error {
r.mu.RLock()
defer r.mu.RUnlock()
return viamutils.TryClose(ctx, r.actual)
}
func (r *reconfigurableSensor) ProxyFor() interface{} {
r.mu.RLock()
defer r.mu.RUnlock()
return r.actual
}
// DoCommand passes generic commands/data.
func (r *reconfigurableSensor) DoCommand(ctx context.Context, cmd map[string]interface{}) (map[string]interface{}, error) {
r.mu.RLock()
defer r.mu.RUnlock()
return r.actual.DoCommand(ctx, cmd)
}
func (r *reconfigurableSensor) Readings(ctx context.Context, extra map[string]interface{}) (map[string]interface{}, error) {
r.mu.RLock()
defer r.mu.RUnlock()
return r.actual.Readings(ctx, extra)
}
func (r *reconfigurableSensor) Reconfigure(ctx context.Context, newSensor resource.Reconfigurable) error {
r.mu.Lock()
defer r.mu.Unlock()
actual, ok := newSensor.(*reconfigurableSensor)
if !ok {
return utils.NewUnexpectedTypeError(r, newSensor)
}
if err := viamutils.TryClose(ctx, r.actual); err != nil {
golog.Global().Errorw("error closing old", "error", err)
}
r.actual = actual.actual
return nil
}
// WrapWithReconfigurable converts a regular Sensor implementation to a reconfigurableSensor.
// If Sensor is already a reconfigurableSensor, then nothing is done.
func WrapWithReconfigurable(r interface{}, name resource.Name) (resource.Reconfigurable, error) {
Sensor, ok := r.(Sensor)
if !ok {
return nil, NewUnimplementedInterfaceError(r)
}
if reconfigurable, ok := Sensor.(*reconfigurableSensor); ok {
return reconfigurable, nil
}
return &reconfigurableSensor{name: name, actual: Sensor}, nil
}