From 044c34ad71d4dab0bafcfbea84e23c749abd1963 Mon Sep 17 00:00:00 2001 From: luomengY <2938893385@qq.com> Date: Wed, 6 Dec 2023 11:06:02 +0800 Subject: [PATCH] add usbcamera-dmi Signed-off-by: luomengY <2938893385@qq.com> --- mappers/usbcamera-dmi/Dockerfile | 20 + mappers/usbcamera-dmi/Makefile | 34 + mappers/usbcamera-dmi/cmd/main.go | 67 + mappers/usbcamera-dmi/config.yaml | 12 + .../data/dbmethod/influxdb2/client.go | 115 + .../data/dbmethod/redis/client.go | 48 + .../usbcamera-dmi/data/publish/http/client.go | 73 + .../usbcamera-dmi/data/publish/mqtt/client.go | 63 + mappers/usbcamera-dmi/device/device.go | 483 +++ mappers/usbcamera-dmi/device/devicetwin.go | 106 + mappers/usbcamera-dmi/driver/consant.go | 26 + mappers/usbcamera-dmi/driver/devicetype.go | 47 + mappers/usbcamera-dmi/driver/driver.go | 101 + mappers/usbcamera-dmi/driver/uilts.go | 60 + mappers/usbcamera-dmi/hack/lib/init.sh | 32 + mappers/usbcamera-dmi/hack/lib/install.sh | 94 + mappers/usbcamera-dmi/hack/lib/lint.sh | 71 + mappers/usbcamera-dmi/hack/lib/util.sh | 76 + .../usbcamera-dmi/hack/make-rules/mapper.sh | 159 + .../usbcamera-dmi/pkg/common/configmaptype.go | 122 + mappers/usbcamera-dmi/pkg/common/const.go | 43 + .../usbcamera-dmi/pkg/common/dataconverter.go | 169 + mappers/usbcamera-dmi/pkg/common/datamodel.go | 57 + mappers/usbcamera-dmi/pkg/common/event.go | 65 + mappers/usbcamera-dmi/pkg/common/eventtype.go | 106 + mappers/usbcamera-dmi/pkg/config/config.go | 99 + mappers/usbcamera-dmi/pkg/dmi-api/api.pb.go | 3242 +++++++++++++++++ mappers/usbcamera-dmi/pkg/dmi-api/api.proto | 365 ++ .../usbcamera-dmi/pkg/dmi-api/api_grpc.pb.go | 559 +++ mappers/usbcamera-dmi/pkg/global/global.go | 58 + .../usbcamera-dmi/pkg/grpcserver/device.go | 159 + .../usbcamera-dmi/pkg/grpcserver/server.go | 79 + .../usbcamera-dmi/pkg/httpserver/callback.go | 86 + .../pkg/httpserver/responsetype.go | 45 + .../usbcamera-dmi/pkg/httpserver/restapi.go | 46 + .../usbcamera-dmi/pkg/httpserver/router.go | 17 + .../usbcamera-dmi/pkg/httpserver/server.go | 170 + .../pkg/util/grpcclient/config.go | 12 + .../pkg/util/grpcclient/register.go | 60 + .../pkg/util/grpcclient/report.go | 43 + mappers/usbcamera-dmi/pkg/util/parse/grpc.go | 264 ++ mappers/usbcamera-dmi/pkg/util/parse/parse.go | 68 + mappers/usbcamera-dmi/pkg/util/parse/type.go | 99 + .../usbcamera-dmi/usbmapper-chart/.helmignore | 23 + .../usbcamera-dmi/usbmapper-chart/Chart.yaml | 29 + .../usbmapper-chart/charts/mapper/.helmignore | 23 + .../usbmapper-chart/charts/mapper/Chart.yaml | 28 + .../mapper/charts/device-model/.helmignore | 23 + .../mapper/charts/device-model/Chart.yaml | 24 + .../templates/000-pre-install-hook.yaml | 80 + .../001-camera-usb-device-model.yaml | 83 + .../mapper/charts/device-model/values.yaml | 0 .../templates/002-mapper-deployment.yaml | 97 + .../usbmapper-chart/charts/mapper/values.yaml | 0 .../templates/003-influxdb-volume.yaml | 54 + .../templates/004-influxdb-statefulset.yaml | 97 + .../templates/005-redis-volume.yaml | 51 + .../templates/006-redis-statefulset.yaml | 129 + .../007-camera-usb-device-instance.yaml | 213 ++ .../usbmapper-chart/templates/_helpers.tpl | 65 + .../usbcamera-dmi/usbmapper-chart/values.yaml | 125 + pkg/global/global.go | 13 + 62 files changed, 8877 insertions(+) create mode 100755 mappers/usbcamera-dmi/Dockerfile create mode 100755 mappers/usbcamera-dmi/Makefile create mode 100755 mappers/usbcamera-dmi/cmd/main.go create mode 100755 mappers/usbcamera-dmi/config.yaml create mode 100755 mappers/usbcamera-dmi/data/dbmethod/influxdb2/client.go create mode 100755 mappers/usbcamera-dmi/data/dbmethod/redis/client.go create mode 100755 mappers/usbcamera-dmi/data/publish/http/client.go create mode 100755 mappers/usbcamera-dmi/data/publish/mqtt/client.go create mode 100755 mappers/usbcamera-dmi/device/device.go create mode 100755 mappers/usbcamera-dmi/device/devicetwin.go create mode 100755 mappers/usbcamera-dmi/driver/consant.go create mode 100755 mappers/usbcamera-dmi/driver/devicetype.go create mode 100755 mappers/usbcamera-dmi/driver/driver.go create mode 100755 mappers/usbcamera-dmi/driver/uilts.go create mode 100755 mappers/usbcamera-dmi/hack/lib/init.sh create mode 100755 mappers/usbcamera-dmi/hack/lib/install.sh create mode 100755 mappers/usbcamera-dmi/hack/lib/lint.sh create mode 100755 mappers/usbcamera-dmi/hack/lib/util.sh create mode 100755 mappers/usbcamera-dmi/hack/make-rules/mapper.sh create mode 100755 mappers/usbcamera-dmi/pkg/common/configmaptype.go create mode 100755 mappers/usbcamera-dmi/pkg/common/const.go create mode 100755 mappers/usbcamera-dmi/pkg/common/dataconverter.go create mode 100755 mappers/usbcamera-dmi/pkg/common/datamodel.go create mode 100755 mappers/usbcamera-dmi/pkg/common/event.go create mode 100755 mappers/usbcamera-dmi/pkg/common/eventtype.go create mode 100755 mappers/usbcamera-dmi/pkg/config/config.go create mode 100755 mappers/usbcamera-dmi/pkg/dmi-api/api.pb.go create mode 100755 mappers/usbcamera-dmi/pkg/dmi-api/api.proto create mode 100755 mappers/usbcamera-dmi/pkg/dmi-api/api_grpc.pb.go create mode 100755 mappers/usbcamera-dmi/pkg/global/global.go create mode 100755 mappers/usbcamera-dmi/pkg/grpcserver/device.go create mode 100755 mappers/usbcamera-dmi/pkg/grpcserver/server.go create mode 100755 mappers/usbcamera-dmi/pkg/httpserver/callback.go create mode 100755 mappers/usbcamera-dmi/pkg/httpserver/responsetype.go create mode 100755 mappers/usbcamera-dmi/pkg/httpserver/restapi.go create mode 100755 mappers/usbcamera-dmi/pkg/httpserver/router.go create mode 100755 mappers/usbcamera-dmi/pkg/httpserver/server.go create mode 100755 mappers/usbcamera-dmi/pkg/util/grpcclient/config.go create mode 100755 mappers/usbcamera-dmi/pkg/util/grpcclient/register.go create mode 100755 mappers/usbcamera-dmi/pkg/util/grpcclient/report.go create mode 100755 mappers/usbcamera-dmi/pkg/util/parse/grpc.go create mode 100755 mappers/usbcamera-dmi/pkg/util/parse/parse.go create mode 100755 mappers/usbcamera-dmi/pkg/util/parse/type.go create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/.helmignore create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/Chart.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/.helmignore create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/Chart.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/.helmignore create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/Chart.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/templates/000-pre-install-hook.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/templates/001-camera-usb-device-model.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/values.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/templates/002-mapper-deployment.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/values.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/templates/003-influxdb-volume.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/templates/004-influxdb-statefulset.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/templates/005-redis-volume.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/templates/006-redis-statefulset.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/templates/007-camera-usb-device-instance.yaml create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/templates/_helpers.tpl create mode 100755 mappers/usbcamera-dmi/usbmapper-chart/values.yaml diff --git a/mappers/usbcamera-dmi/Dockerfile b/mappers/usbcamera-dmi/Dockerfile new file mode 100755 index 00000000..89080f7d --- /dev/null +++ b/mappers/usbcamera-dmi/Dockerfile @@ -0,0 +1,20 @@ +FROM golang:1.17-alpine AS builder + +WORKDIR /build + +ENV GO111MODULE=on \ + GOPROXY=https://goproxy.cn,direct + +COPY . . + +RUN CGO_ENABLED=0 GOOS=linux go build -gcflags "all=-N -l" -o main cmd/main.go + + +FROM ubuntu:16.04 + +RUN mkdir -p kubeedge + +COPY --from=builder /build/main kubeedge/ +COPY ./config.yaml kubeedge/ + +WORKDIR kubeedge diff --git a/mappers/usbcamera-dmi/Makefile b/mappers/usbcamera-dmi/Makefile new file mode 100755 index 00000000..4dbacfe2 --- /dev/null +++ b/mappers/usbcamera-dmi/Makefile @@ -0,0 +1,34 @@ +SHELL := /bin/bash + +curr_dir := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) +rest_args := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS)) +$(eval $(rest_args):;@:) + +help: + # + # Usage: + # make generate : generate a mapper based on a template. + # make mapper {mapper-name} : execute mapper building process. + # + # Actions: + # - mod, m : download code dependencies. + # - lint, l : verify code via go fmt and `golangci-lint`. + # - build, b : compile code. + # - package, p : package docker image. + # - clean, c : clean output binary. + # + # Parameters: + # ARM : true or undefined + # ARM64 : true or undefined + # + # Example: + # - make mapper modbus ARM64=true : execute `build` "modbus" mapper for ARM64. + # - make mapper modbus test : execute `test` "modbus" mapper. + @echo + +make_rules := $(shell ls $(curr_dir)/hack/make-rules | sed 's/.sh//g') +$(make_rules): + @$(curr_dir)/hack/make-rules/$@.sh $(rest_args) + +.DEFAULT_GOAL := help +.PHONY: $(make_rules) build test package \ No newline at end of file diff --git a/mappers/usbcamera-dmi/cmd/main.go b/mappers/usbcamera-dmi/cmd/main.go new file mode 100755 index 00000000..79a408a5 --- /dev/null +++ b/mappers/usbcamera-dmi/cmd/main.go @@ -0,0 +1,67 @@ +package main + +import ( + "errors" + "os" + + "k8s.io/klog/v2" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/device" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/config" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/grpcserver" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/httpserver" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/util/grpcclient" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/util/parse" +) + +func main() { + var err error + var c config.Config + + klog.InitFlags(nil) + defer klog.Flush() + + if err = c.Parse(); err != nil { + klog.Fatal(err) + os.Exit(1) + } + klog.Infof("config: %+v", c) + + grpcclient.Init(&c) + + // start grpc server + grpcServer := grpcserver.NewServer( + grpcserver.Config{ + SockPath: c.GrpcServer.SocketPath, + Protocol: common.ProtocolCustomized, + }, + device.NewDevPanel(), + ) + + panel := device.NewDevPanel() + err = panel.DevInit(&c) + if err != nil && !errors.Is(err, parse.ErrEmptyData) { + klog.Fatal(err) + } + klog.Infoln("devInit finished") + + // register to edgecore + // if dev init mode is register, mapper's dev will init when registry to edgecore + if c.DevInit.Mode != common.DevInitModeRegister { + klog.Infoln("======dev init mode is not register, will register to edgecore") + if _, _, err = grpcclient.RegisterMapper(&c, false); err != nil { + klog.Fatal(err) + } + klog.Infoln("registerMapper finished") + } + go panel.DevStart() + + httpServer := httpserver.NewRestServer(panel) + go httpServer.StartServer() + + defer grpcServer.Stop() + if err = grpcServer.Start(); err != nil { + klog.Fatal(err) + } +} diff --git a/mappers/usbcamera-dmi/config.yaml b/mappers/usbcamera-dmi/config.yaml new file mode 100755 index 00000000..b74d098b --- /dev/null +++ b/mappers/usbcamera-dmi/config.yaml @@ -0,0 +1,12 @@ +grpc_server: + socket_path: /etc/kubeedge/usb.sock +common: + name: Usb-mapper + version: v1.13.0 + api_version: v1.0.0 + protocol: camera-usb # TODO add your protocol name + address: 127.0.0.1 + edgecore_sock: /etc/kubeedge/dmi.sock +dev_init: + mode: register + diff --git a/mappers/usbcamera-dmi/data/dbmethod/influxdb2/client.go b/mappers/usbcamera-dmi/data/dbmethod/influxdb2/client.go new file mode 100755 index 00000000..aff6ff1e --- /dev/null +++ b/mappers/usbcamera-dmi/data/dbmethod/influxdb2/client.go @@ -0,0 +1,115 @@ +package influxdb2 + +import ( + "context" + "encoding/json" + "fmt" + "os" + "strings" + "time" + + "k8s.io/klog/v2" + + influxdb2 "github.com/influxdata/influxdb-client-go/v2" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" +) + +type DataBaseConfig struct { + Influxdb2ClientConfig *Influxdb2ClientConfig `json:"influxdb2ClientConfig,omitempty"` + Influxdb2DataConfig *Influxdb2DataConfig `json:"influxdb2DataConfig,omitempty"` +} + +type Influxdb2ClientConfig struct { + Url string `json:"url,omitempty"` + Org string `json:"org,omitempty"` + Bucket string `json:"bucket,omitempty"` +} + +type Influxdb2DataConfig struct { + Measurement string `json:"measurement,omitempty"` + Tag map[string]string `json:"tag,omitempty"` + FieldKey string `json:"fieldKey,omitempty"` +} + +func NewDataBaseClient(clientConfig json.RawMessage, dataConfig json.RawMessage) (*DataBaseConfig, error) { + // parse influx database config data + influxdb2ClientConfig := new(Influxdb2ClientConfig) + influxdb2DataConfig := new(Influxdb2DataConfig) + err := json.Unmarshal(clientConfig, influxdb2ClientConfig) + if err != nil { + return nil, err + } + err = json.Unmarshal(dataConfig, influxdb2DataConfig) + if err != nil { + return nil, err + } + return &DataBaseConfig{ + Influxdb2ClientConfig: influxdb2ClientConfig, + Influxdb2DataConfig: influxdb2DataConfig, + }, nil +} + +func (d *DataBaseConfig) InitDbClient() influxdb2.Client { + var usrtoken string + usrtoken = os.Getenv("TOKEN") + client := influxdb2.NewClient(d.Influxdb2ClientConfig.Url, usrtoken) + + return client +} + +func (d *DataBaseConfig) CloseSession(client influxdb2.Client) { + client.Close() +} + +func (d *DataBaseConfig) AddData(data *common.DataModel, client influxdb2.Client) error { + // write device data to influx database + orgName := d.Influxdb2ClientConfig.Org + bucketName := d.Influxdb2ClientConfig.Bucket + ctx := context.Background() + errMark := "not found" + org, err := client.OrganizationsAPI().FindOrganizationByName(ctx, orgName) + if err != nil { + if strings.Contains(err.Error(), errMark) { + org, err := client.OrganizationsAPI().CreateOrganizationWithName(ctx, orgName) + if err != nil { + return fmt.Errorf("create organization '%s' faild with err:%v", orgName, err) + } + _, err = client.BucketsAPI().CreateBucketWithName(ctx, org, bucketName) + if err != nil { + return fmt.Errorf("create bucket '%s' faild with err:%v", bucketName, err) + } + } else { + return fmt.Errorf("find organization '%s' faild with err:%v", orgName, err) + } + } else { + buckets, err := client.BucketsAPI().FindBucketsByOrgName(ctx, orgName) + if err != nil { + return fmt.Errorf("find buckets faild with err:%v", err) + } + var flag = false + for _, bucket := range *buckets { + if bucket.Name == bucketName { + flag = true + break + } + } + if !flag { + _, err = client.BucketsAPI().CreateBucketWithName(ctx, org, bucketName) + if err != nil { + return fmt.Errorf("create bucket '%s' faild with err:%v", bucketName, err) + } + } + } + writeAPI := client.WriteAPIBlocking(d.Influxdb2ClientConfig.Org, d.Influxdb2ClientConfig.Bucket) + p := influxdb2.NewPoint(d.Influxdb2DataConfig.Measurement, + d.Influxdb2DataConfig.Tag, + map[string]interface{}{d.Influxdb2DataConfig.FieldKey: data.Value}, + time.Now()) + // write point immediately + err = writeAPI.WritePoint(context.Background(), p) + if err != nil { + klog.V(4).Info("Exit AddData") + return err + } + return nil +} diff --git a/mappers/usbcamera-dmi/data/dbmethod/redis/client.go b/mappers/usbcamera-dmi/data/dbmethod/redis/client.go new file mode 100755 index 00000000..ef762554 --- /dev/null +++ b/mappers/usbcamera-dmi/data/dbmethod/redis/client.go @@ -0,0 +1,48 @@ +package redis + +import ( + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/global" +) + +type DataBaseConfig struct { +} + +func NewDataBaseClient() (global.DataBaseClient, error) { + return &DataBaseConfig{}, nil +} + +func (d *DataBaseConfig) InitDbClient() error { + //TODO implement me + panic("implement me") +} + +func (d *DataBaseConfig) CloseSession() { + //TODO implement me + panic("implement me") +} + +func (d *DataBaseConfig) AddData(data *common.DataModel) { + //TODO implement me + panic("implement me") +} + +func (d *DataBaseConfig) GetDataByDeviceName(deviceName string) ([]*common.DataModel, error) { + //TODO implement me + panic("implement me") +} + +func (d *DataBaseConfig) GetPropertyDataByDeviceName(deviceName string, propertyData string) ([]*common.DataModel, error) { + //TODO implement me + panic("implement me") +} + +func (d *DataBaseConfig) GetDataByTimeRange(start int64, end int64) ([]*common.DataModel, error) { + //TODO implement me + panic("implement me") +} + +func (d *DataBaseConfig) DeleteDataByTimeRange(start int64, end int64) ([]*common.DataModel, error) { + //TODO implement me + panic("implement me") +} diff --git a/mappers/usbcamera-dmi/data/publish/http/client.go b/mappers/usbcamera-dmi/data/publish/http/client.go new file mode 100755 index 00000000..98b2da37 --- /dev/null +++ b/mappers/usbcamera-dmi/data/publish/http/client.go @@ -0,0 +1,73 @@ +package http + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strconv" + "strings" + "time" + + "k8s.io/klog/v2" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/global" +) + +type PushMethod struct { + HTTP *HTTPConfig `json:"http"` +} + +type HTTPConfig struct { + HostName string `json:"hostName,omitempty"` + Port int `json:"port,omitempty"` + RequestPath string `json:"requestPath,omitempty"` + Timeout int `json:"timeout,omitempty"` +} + +func NewDataPanel(config json.RawMessage) (global.DataPanel, error) { + httpConfig := new(HTTPConfig) + err := json.Unmarshal(config, httpConfig) + if err != nil { + return nil, err + } + return &PushMethod{ + HTTP: httpConfig, + }, nil +} + +func (pm *PushMethod) InitPushMethod() error { + klog.V(1).Info("Init HTTP") + return nil +} + +func (pm *PushMethod) Push(data *common.DataModel) { + klog.V(2).Info("Publish device data by HTTP") + + targetUrl := pm.HTTP.HostName + ":" + strconv.Itoa(pm.HTTP.Port) + pm.HTTP.RequestPath + payload := data.PropertyName + "=" + data.Value + formatTimeStr := time.Unix(data.TimeStamp/1e3, 0).Format("2006-01-02 15:04:05") + currentTime := "&time" + "=" + formatTimeStr + payload += currentTime + + klog.V(3).Infof("Publish %v to %s", payload, targetUrl) + + resp, err := http.Post(targetUrl, + "application/x-www-form-urlencoded", + strings.NewReader(payload)) + + if err != nil { + fmt.Println(err) + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + // handle error + klog.Errorf("Publish device data by HTTP failed, err = %v", err) + return + } + klog.V(1).Info("############### Message published. ###############") + klog.V(3).Infof("HTTP reviced %s", string(body)) + +} diff --git a/mappers/usbcamera-dmi/data/publish/mqtt/client.go b/mappers/usbcamera-dmi/data/publish/mqtt/client.go new file mode 100755 index 00000000..53f523fc --- /dev/null +++ b/mappers/usbcamera-dmi/data/publish/mqtt/client.go @@ -0,0 +1,63 @@ +package mqtt + +import ( + "encoding/json" + "fmt" + "os" + "time" + + mqtt "github.com/eclipse/paho.mqtt.golang" + "k8s.io/klog/v2" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/global" +) + +type PushMethod struct { + MQTT *MQTTConfig `json:"http"` +} + +type MQTTConfig struct { + Address string `json:"address,omitempty"` + Topic string `json:"topic,omitempty"` + QoS int `json:"qos,omitempty"` + Retained bool `json:"retained,omitempty"` +} + +func NewDataPanel(config json.RawMessage) (global.DataPanel, error) { + mqttConfig := new(MQTTConfig) + err := json.Unmarshal(config, mqttConfig) + if err != nil { + return nil, err + } + return &PushMethod{ + MQTT: mqttConfig, + }, nil +} + +func (pm *PushMethod) InitPushMethod() error { + klog.V(1).Info("Init MQTT") + return nil +} + +func (pm *PushMethod) Push(data *common.DataModel) { + klog.V(1).Infof("Publish %v to %s on topic: %s, Qos: %d, Retained: %v", + data.Value, pm.MQTT.Address, pm.MQTT.Topic, pm.MQTT.QoS, pm.MQTT.Retained) + + opts := mqtt.NewClientOptions().AddBroker(pm.MQTT.Address) + client := mqtt.NewClient(opts) + + if token := client.Connect(); token.Wait() && token.Error() != nil { + fmt.Println(token.Error()) + os.Exit(1) + } + formatTimeStr := time.Unix(data.TimeStamp/1e3, 0).Format("2006-01-02 15:04:05") + str_time := "time is " + formatTimeStr + " " + str_publish := str_time + pm.MQTT.Topic + ": " + data.Value + + token := client.Publish(pm.MQTT.Topic, byte(pm.MQTT.QoS), pm.MQTT.Retained, str_publish) + token.Wait() + + client.Disconnect(250) + klog.V(2).Info("############### Message published. ###############") +} diff --git a/mappers/usbcamera-dmi/device/device.go b/mappers/usbcamera-dmi/device/device.go new file mode 100755 index 00000000..fe66fe9e --- /dev/null +++ b/mappers/usbcamera-dmi/device/device.go @@ -0,0 +1,483 @@ +package device + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "os" + "os/signal" + "strings" + "sync" + "time" + + "k8s.io/klog/v2" + + dbInflux "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/data/dbmethod/influxdb2" + httpMethod "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/data/publish/http" + mqttMethod "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/data/publish/mqtt" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/driver" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/config" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/global" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/util/parse" +) + +type DevPanel struct { + deviceMuxs map[string]context.CancelFunc + devices map[string]*driver.CustomizedDev + models map[string]common.DeviceModel + protocols map[string]common.ProtocolConfig + wg sync.WaitGroup + serviceMutex sync.Mutex + quitChan chan os.Signal +} + +var ( + devPanel *DevPanel + once sync.Once +) + +// NewDevPanel init and return devPanel +func NewDevPanel() *DevPanel { + once.Do(func() { + devPanel = &DevPanel{ + deviceMuxs: make(map[string]context.CancelFunc), + devices: make(map[string]*driver.CustomizedDev), + models: make(map[string]common.DeviceModel), + protocols: make(map[string]common.ProtocolConfig), + wg: sync.WaitGroup{}, + serviceMutex: sync.Mutex{}, + quitChan: make(chan os.Signal), + } + }) + return devPanel +} + +// DevStart start all devices. +func (d *DevPanel) DevStart() { + for id, dev := range d.devices { + klog.V(4).Info("Dev: ", id, dev) + ctx, cancel := context.WithCancel(context.Background()) + d.deviceMuxs[id] = cancel + d.wg.Add(1) + go d.start(ctx, dev) + } + signal.Notify(d.quitChan, os.Interrupt) + go func() { + <-d.quitChan + for id, device := range d.devices { + err := device.CustomizedClient.StopDevice() + if err != nil { + klog.Errorf("Service has stopped but failed to stop %s:%v", id, err) + } + } + klog.V(1).Info("Exit mapper") + os.Exit(1) + }() + d.wg.Wait() +} + +// start the device +func (d *DevPanel) start(ctx context.Context, dev *driver.CustomizedDev) { + defer d.wg.Done() + + var protocolConfig driver.ProtocolConfig + if err := json.Unmarshal(dev.Instance.PProtocol.ConfigData, &protocolConfig); err != nil { + klog.Errorf("Unmarshal ProtocolConfigs error: %v", err) + return + } + client, err := driver.NewClient(protocolConfig) + if err != nil { + klog.Errorf("Init dev %s error: %v", dev.Instance.Name, err) + return + } + dev.CustomizedClient = client + err = dev.CustomizedClient.InitDevice() + if err != nil { + klog.Errorf("Init device %s error: %v", dev.Instance.ID, err) + return + } + go dataHandler(ctx, dev) + <-ctx.Done() +} + +// dataHandler initialize the timer to handle data plane and devicetwin. +func dataHandler(ctx context.Context, dev *driver.CustomizedDev) { + for _, twin := range dev.Instance.Twins { + twin.Property.PProperty.DataType = strings.ToLower(twin.Property.PProperty.DataType) + var visitorConfig driver.VisitorConfig + + err := json.Unmarshal(twin.Property.Visitors, &visitorConfig) + visitorConfig.VisitorConfigData.DataType = strings.ToLower(visitorConfig.VisitorConfigData.DataType) + if err != nil { + klog.Errorf("Unmarshal VisitorConfig error: %v", err) + continue + } + err = setVisitor(&visitorConfig, &twin, dev) + if err != nil { + klog.Error(err) + continue + } + // handle twin + twinData := &TwinData{ + DeviceName: dev.Instance.Name, + Client: dev.CustomizedClient, + Name: twin.PropertyName, + Type: twin.ObservedDesired.Metadata.Type, + ObservedDesired: twin.ObservedDesired, + VisitorConfig: &visitorConfig, + Topic: fmt.Sprintf(common.TopicTwinUpdate, dev.Instance.ID), + CollectCycle: time.Duration(twin.Property.CollectCycle), + ReportToCloud: twin.Property.ReportToCloud, + } + go twinData.Run(ctx) + // handle push method + if twin.Property.PushMethod.MethodConfig != nil && twin.Property.PushMethod.MethodName != "" { + dataModel := common.NewDataModel(dev.Instance.Name, twin.Property.PropertyName, common.WithType(twin.ObservedDesired.Metadata.Type)) + pushHandler(ctx, &twin, dev.CustomizedClient, &visitorConfig, dataModel) + } + // handle database + if twin.Property.PushMethod.DBMethod.DBMethodName != "" { + dataModel := common.NewDataModel(dev.Instance.Name, twin.Property.PropertyName, common.WithType(twin.ObservedDesired.Metadata.Type)) + dbHandler(ctx, &twin, dev.CustomizedClient, &visitorConfig, dataModel) + } + } +} + +// pushHandler start data panel work +func pushHandler(ctx context.Context, twin *common.Twin, client *driver.CustomizedClient, visitorConfig *driver.VisitorConfig, dataModel *common.DataModel) { + var dataPanel global.DataPanel + var err error + // initialization dataPanel + switch twin.Property.PushMethod.MethodName { + case "http": + dataPanel, err = httpMethod.NewDataPanel(twin.Property.PushMethod.MethodConfig) + case "mqtt": + dataPanel, err = mqttMethod.NewDataPanel(twin.Property.PushMethod.MethodConfig) + default: + err = errors.New("custom protocols are not currently supported when push data") + } + if err != nil { + klog.Errorf("new data panel error: %v", err) + return + } + // initialization PushMethod + err = dataPanel.InitPushMethod() + if err != nil { + klog.Errorf("init publish method err: %v", err) + return + } + reportCycle := time.Duration(twin.Property.ReportCycle) + if reportCycle == 0 { + reportCycle = 1 * time.Second + } + ticker := time.NewTicker(reportCycle) + go func() { + for { + select { + case <-ticker.C: + deviceData, err := client.GetDeviceData(visitorConfig) + if err != nil { + klog.Errorf("publish error: %v", err) + continue + } + sData, err := common.ConvertToString(deviceData) + if err != nil { + klog.Errorf("Failed to convert publish method data : %v", err) + continue + } + dataModel.SetValue(sData) + dataModel.SetTimeStamp() + dataPanel.Push(dataModel) + case <-ctx.Done(): + return + } + } + }() +} + +// dbHandler start db client to save data +func dbHandler(ctx context.Context, twin *common.Twin, client *driver.CustomizedClient, visitorConfig *driver.VisitorConfig, dataModel *common.DataModel) { + switch twin.Property.PushMethod.DBMethod.DBMethodName { + // TODO add more database + case "influx": + dbConfig, err := dbInflux.NewDataBaseClient(twin.Property.PushMethod.DBMethod.DBConfig.Influxdb2ClientConfig, twin.Property.PushMethod.DBMethod.DBConfig.Influxdb2DataConfig) + if err != nil { + klog.Errorf("new database client error: %v", err) + return + } + dbClient := dbConfig.InitDbClient() + if err != nil { + klog.Errorf("init database client err: %v", err) + return + } + reportCycle := time.Duration(twin.Property.ReportCycle) + if reportCycle == 0 { + reportCycle = 1 * time.Second + } + ticker := time.NewTicker(reportCycle) + go func() { + for { + select { + case <-ticker.C: + deviceData, err := client.GetDeviceData(visitorConfig) + if err != nil { + klog.Errorf("publish error: %v", err) + continue + } + sData, err := common.ConvertToString(deviceData) + if err != nil { + klog.Errorf("Failed to convert publish method data : %v", err) + continue + } + dataModel.SetValue(sData) + dataModel.SetTimeStamp() + + err = dbConfig.AddData(dataModel, dbClient) + if err != nil { + klog.Errorf("influx database add data error: %v", err) + return + } + case <-ctx.Done(): + dbConfig.CloseSession(dbClient) + return + } + } + }() + } +} + +// setVisitor check if visitor property is readonly, if not then set it. +func setVisitor(visitorConfig *driver.VisitorConfig, twin *common.Twin, dev *driver.CustomizedDev) error { + if twin.Property.PProperty.AccessMode == "ReadOnly" { + klog.V(3).Infof("%s twin readonly property: %s", dev.Instance.Name, twin.PropertyName) + return nil + } + klog.V(2).Infof("Convert type: %s, value: %s ", twin.Property.PProperty.DataType, twin.ObservedDesired.Value) + value, err := common.Convert(twin.Property.PProperty.DataType, twin.ObservedDesired.Value) + if err != nil { + klog.Errorf("Failed to convert value as %s : %v", twin.Property.PProperty.DataType, err) + return err + } + err = dev.CustomizedClient.SetDeviceData(value, visitorConfig) + if err != nil { + return fmt.Errorf("%s set device data error: %v", twin.PropertyName, err) + } + return nil +} + +// DevInit initialize the device +func (d *DevPanel) DevInit(cfg *config.Config) error { + devs := make(map[string]*common.DeviceInstance) + + switch cfg.DevInit.Mode { + //case common.DevInitModeConfigmap: + // if err := parse.Parse(cfg.DevInit.Configmap, devs, d.models, d.protocols); err != nil { + // return err + // } + case common.DevInitModeRegister: + if err := parse.ParseByUsingRegister(cfg, devs, d.models, d.protocols); err != nil { + return err + } + } + + for key, deviceInstance := range devs { + cur := new(driver.CustomizedDev) + cur.Instance = *deviceInstance + d.devices[key] = cur + } + return nil +} + +// UpdateDev stop old device, then update and start new device +func (d *DevPanel) UpdateDev(model *common.DeviceModel, device *common.DeviceInstance, protocol *common.ProtocolConfig) { + d.serviceMutex.Lock() + defer d.serviceMutex.Unlock() + + if oldDevice, ok := d.devices[device.ID]; ok { + err := d.stopDev(oldDevice, device.ID) + if err != nil { + klog.Error(err) + } + } + // start new device + d.devices[device.ID] = new(driver.CustomizedDev) + d.devices[device.ID].Instance = *device + d.models[device.ID] = *model + d.protocols[device.ID] = *protocol + + ctx, cancelFunc := context.WithCancel(context.Background()) + d.deviceMuxs[device.ID] = cancelFunc + d.wg.Add(1) + go d.start(ctx, d.devices[device.ID]) +} + +// UpdateDevTwins update device's twins +func (d *DevPanel) UpdateDevTwins(deviceID string, twins []common.Twin) error { + d.serviceMutex.Lock() + defer d.serviceMutex.Unlock() + dev, ok := d.devices[deviceID] + if !ok { + return fmt.Errorf("device %s not found", deviceID) + } + dev.Instance.Twins = twins + model := d.models[dev.Instance.Model] + protocol := d.protocols[dev.Instance.ProtocolName] + d.UpdateDev(&model, &dev.Instance, &protocol) + return nil +} + +// DealDeviceTwinGet get device's twin data +func (d *DevPanel) DealDeviceTwinGet(deviceID string, twinName string) (interface{}, error) { + d.serviceMutex.Lock() + defer d.serviceMutex.Unlock() + dev, ok := d.devices[deviceID] + if !ok { + return nil, fmt.Errorf("not found device %s", deviceID) + } + var res []parse.TwinResultResponse + for _, twin := range dev.Instance.Twins { + if twinName != "" && twin.PropertyName != twinName { + continue + } + payload, err := getTwinData(deviceID, twin, d.devices[deviceID]) + if err != nil { + return nil, err + } + item := parse.TwinResultResponse{ + PropertyName: twinName, + Payload: payload, + } + res = append(res, item) + } + return json.Marshal(res) +} + +// getTwinData get twin +func getTwinData(deviceID string, twin common.Twin, dev *driver.CustomizedDev) ([]byte, error) { + var visitorConfig driver.VisitorConfig + err := json.Unmarshal(twin.Property.Visitors, &visitorConfig) + if err != nil { + return nil, err + } + err = setVisitor(&visitorConfig, &twin, dev) + if err != nil { + return nil, err + } + twinData := &TwinData{ + DeviceName: deviceID, + Client: dev.CustomizedClient, + Name: twin.PropertyName, + Type: twin.ObservedDesired.Metadata.Type, + VisitorConfig: &visitorConfig, + Topic: fmt.Sprintf(common.TopicTwinUpdate, deviceID), + } + return twinData.GetPayLoad() +} + +// GetDevice get device instance +func (d *DevPanel) GetDevice(deviceID string) (interface{}, error) { + d.serviceMutex.Lock() + defer d.serviceMutex.Unlock() + found, ok := d.devices[deviceID] + if !ok || found == nil { + return nil, fmt.Errorf("device %s not found", deviceID) + } + + // get the latest reported twin value + for i, twin := range found.Instance.Twins { + payload, err := getTwinData(deviceID, twin, found) + if err != nil { + return nil, err + } + found.Instance.Twins[i].Reported.Value = string(payload) + } + return found, nil +} + +// RemoveDevice remove device instance +func (d *DevPanel) RemoveDevice(deviceID string) error { + d.serviceMutex.Lock() + defer d.serviceMutex.Unlock() + dev := d.devices[deviceID] + delete(d.devices, deviceID) + err := d.stopDev(dev, deviceID) + if err != nil { + return err + } + return nil +} + +// stopDev stop device and goroutine +func (d *DevPanel) stopDev(dev *driver.CustomizedDev, id string) error { + cancelFunc, ok := d.deviceMuxs[id] + if !ok { + return fmt.Errorf("can not find device %s from device muxs", id) + } + + err := dev.CustomizedClient.StopDevice() + if err != nil { + klog.Errorf("stop device %s error: %v", id, err) + } + cancelFunc() + return nil +} + +// GetModel if the model exists, return device model +func (d *DevPanel) GetModel(modelName string) (common.DeviceModel, error) { + d.serviceMutex.Lock() + defer d.serviceMutex.Unlock() + if model, ok := d.models[modelName]; ok { + return model, nil + } + return common.DeviceModel{}, fmt.Errorf("deviceModel %s not found", modelName) +} + +// UpdateModel update device model +func (d *DevPanel) UpdateModel(model *common.DeviceModel) { + d.serviceMutex.Lock() + d.models[model.Name] = *model + d.serviceMutex.Unlock() +} + +// RemoveModel remove device model +func (d *DevPanel) RemoveModel(modelName string) { + d.serviceMutex.Lock() + delete(d.models, modelName) + d.serviceMutex.Unlock() +} + +// GetTwinResult Get twin's value and data type +func (d *DevPanel) GetTwinResult(deviceID string, twinName string) (string, string, error) { + d.serviceMutex.Lock() + defer d.serviceMutex.Unlock() + dev, ok := d.devices[deviceID] + if !ok { + return "", "", fmt.Errorf("not found device %s", deviceID) + } + var res string + var dataType string + for _, twin := range dev.Instance.Twins { + if twinName != "" && twin.PropertyName != twinName { + continue + } + var visitorConfig driver.VisitorConfig + err := json.Unmarshal(twin.Property.Visitors, &visitorConfig) + if err != nil { + return "", "", err + } + err = setVisitor(&visitorConfig, &twin, dev) + + data, err := dev.CustomizedClient.GetDeviceData(&visitorConfig) + if err != nil { + return "", "", fmt.Errorf("get device data failed: %v", err) + } + res, err = common.ConvertToString(data) + if err != nil { + return "", "", err + } + dataType = twin.Property.PProperty.DataType + } + return res, dataType, nil +} diff --git a/mappers/usbcamera-dmi/device/devicetwin.go b/mappers/usbcamera-dmi/device/devicetwin.go new file mode 100755 index 00000000..5cf005c6 --- /dev/null +++ b/mappers/usbcamera-dmi/device/devicetwin.go @@ -0,0 +1,106 @@ +package device + +import ( + "context" + "encoding/json" + "fmt" + "strings" + "time" + + "k8s.io/klog/v2" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/driver" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" + dmiapi "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/dmi-api" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/util/grpcclient" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/util/parse" +) + +type TwinData struct { + DeviceName string + Client *driver.CustomizedClient + Name string + Type string + ObservedDesired common.TwinProperty + VisitorConfig *driver.VisitorConfig + Topic string + Results interface{} + CollectCycle time.Duration + ReportToCloud bool +} + +func (td *TwinData) GetPayLoad() ([]byte, error) { + var err error + td.VisitorConfig.VisitorConfigData.DataType = strings.ToLower(td.VisitorConfig.VisitorConfigData.DataType) + td.Results, err = td.Client.GetDeviceData(td.VisitorConfig) + if err != nil { + return nil, fmt.Errorf("get device data failed: %v", err) + } + sData, err := common.ConvertToString(td.Results) + if err != nil { + klog.Errorf("Failed to convert %s %s value as string : %v", td.DeviceName, td.Name, err) + return nil, err + } + if len(sData) > 30 { + klog.V(4).Infof("Get %s : %s ,value is %s......", td.DeviceName, td.Name, sData[:30]) + } else { + klog.V(4).Infof("Get %s : %s ,value is %s", td.DeviceName, td.Name, sData) + } + var payload []byte + if strings.Contains(td.Topic, "$hw") { + if payload, err = common.CreateMessageTwinUpdate(td.Name, td.Type, sData, td.ObservedDesired.Value); err != nil { + return nil, fmt.Errorf("create message twin update failed: %v", err) + } + } else { + if payload, err = common.CreateMessageData(td.Name, td.Type, sData); err != nil { + return nil, fmt.Errorf("create message data failed: %v", err) + } + } + return payload, nil +} + +func (td *TwinData) PushToEdgeCore() { + payload, err := td.GetPayLoad() + if err != nil { + klog.Errorf("twindata %s unmarshal failed, err: %s", td.Name, err) + return + } + + var msg common.DeviceTwinUpdate + if err = json.Unmarshal(payload, &msg); err != nil { + klog.Errorf("twindata %s unmarshal failed, err: %s", td.Name, err) + return + } + + twins := parse.ConvMsgTwinToGrpc(msg.Twin) + + var rdsr = &dmiapi.ReportDeviceStatusRequest{ + DeviceName: td.DeviceName, + ReportedDevice: &dmiapi.DeviceStatus{ + Twins: twins, + //State: "OK", + }, + } + + if err := grpcclient.ReportDeviceStatus(rdsr); err != nil { + klog.Errorf("fail to report device status of %s with err: %+v", rdsr.DeviceName, err) + } +} + +func (td *TwinData) Run(ctx context.Context) { + if !td.ReportToCloud { + return + } + if td.CollectCycle == 0 { + td.CollectCycle = 1 * time.Second + } + ticker := time.NewTicker(td.CollectCycle) + for { + select { + case <-ticker.C: + td.PushToEdgeCore() + case <-ctx.Done(): + return + } + } +} diff --git a/mappers/usbcamera-dmi/driver/consant.go b/mappers/usbcamera-dmi/driver/consant.go new file mode 100755 index 00000000..51c32dce --- /dev/null +++ b/mappers/usbcamera-dmi/driver/consant.go @@ -0,0 +1,26 @@ +package driver + +const ( + Width = "width" + Height = "height" + GetWidth = "getWith" + GetHeight = "getHeight" + + Framerate = "Framerate" + Input = "Input" + BusInfo = "BusInfo" + BufferCount = "BufferCount" + + WhiteBalanceTemperature = "White Balance Temperature" + WhiteBalanceTemperatureAuto = "White Balance Temperature, Auto" + ExposureAbsolute = "Exposure (Absolute)" + ExposureAuto = "Exposure, Auto" + PowerLineFrequency = "Power Line Frequency" + Sharpness = "Sharpness" + Contrast = "Contrast" + Saturation = "Saturation" + Gain = "Gain" + Brightness = "Brightness" + ImageTrigger = "ImageTrigger" + PixelFormat = "PixelFormat" +) diff --git a/mappers/usbcamera-dmi/driver/devicetype.go b/mappers/usbcamera-dmi/driver/devicetype.go new file mode 100755 index 00000000..3c9878ba --- /dev/null +++ b/mappers/usbcamera-dmi/driver/devicetype.go @@ -0,0 +1,47 @@ +package driver + +import ( + "sync" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" +) + +// CustomizedDev is the customized device configuration and client information. +type CustomizedDev struct { + Instance common.DeviceInstance + CustomizedClient *CustomizedClient +} + +type CustomizedClient struct { + // TODO add some variables to help you better implement device drivers + deviceMutex sync.Mutex + ProtocolConfig +} + +type ProtocolConfig struct { + ProtocolName string `json:"protocolName"` + ConfigData `json:"configData"` +} + +type ConfigData struct { + // TODO: add your protocol config data + SerialPort string `json:"serialPort"` + + DeviceID int `json:"deviceID,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + Format int `json:"format,omitempty"` + + ProtocolID int `json:"protocolID"` +} + +type VisitorConfig struct { + ProtocolName string `json:"protocolName"` + VisitorConfigData `json:"configData"` +} + +type VisitorConfigData struct { + // TODO: add your visitor config data + DataType string `json:"dataType"` + FeatureName string `json:"featureName"` +} diff --git a/mappers/usbcamera-dmi/driver/driver.go b/mappers/usbcamera-dmi/driver/driver.go new file mode 100755 index 00000000..0e41340c --- /dev/null +++ b/mappers/usbcamera-dmi/driver/driver.go @@ -0,0 +1,101 @@ +package driver + +import ( + "sync" + "time" + + "github.com/blackjack/webcam" + "k8s.io/klog/v2" +) + +var Cam *webcam.Webcam + +func NewClient(protocol ProtocolConfig) (*CustomizedClient, error) { + client := &CustomizedClient{ + ProtocolConfig: protocol, + deviceMutex: sync.Mutex{}, + // TODO initialize the variables you added + } + return client, nil +} + +func (c *CustomizedClient) InitDevice() error { + // TODO: add init operation + // you can use c.ProtocolConfig + cam, err := inner(c.SerialPort) + if err != nil { + return err + } + Cam = cam + + return nil +} + +func inner(path string) (*webcam.Webcam, error) { + var cam *webcam.Webcam = nil + var err error + for { + cam, err = webcam.Open(path) + if err == nil { + break + } else { + klog.Errorf("open the carmera failed with err: %v", err) + time.Sleep(1 * time.Second) + } + } + return cam, err +} + +func (c *CustomizedClient) GetDeviceData(visitor *VisitorConfig) (interface{}, error) { + // TODO: add the code to get device's data + // you can use c.ProtocolConfig and visitor + featureName := visitor.FeatureName + switch featureName { + case Framerate: + return Cam.GetFramerate() + case Input: + return Cam.GetInput() + case BusInfo: + return Cam.GetBusInfo() + case Gain, Contrast, Saturation, WhiteBalanceTemperature, + WhiteBalanceTemperatureAuto, Sharpness, PowerLineFrequency, ExposureAuto, ExposureAbsolute, Brightness: + controls := Cam.GetControls() + return GetControl(controls, featureName) + case ImageTrigger: + return GetImage(c.Width, c.Height, c.Format) + } + return nil, nil +} + +func (c *CustomizedClient) SetDeviceData(data interface{}, visitor *VisitorConfig) error { + // TODO: set device's data + // you can use c.ProtocolConfig and visitor + featureName := visitor.FeatureName + switch featureName { + case Framerate: + return Cam.SetFramerate(float32(data.(float64))) + case BufferCount: + return Cam.SetBufferCount(uint32(data.(uint64))) + case Gain, Contrast, Saturation, + WhiteBalanceTemperatureAuto, Sharpness, PowerLineFrequency, ExposureAuto, Brightness: + controls := Cam.GetControls() + return SetControl(controls, featureName, data) + //case Width: + // _, err := GetOrSetSize(data.(int), Width) + // return err + //case Height: + // _, err := GetOrSetSize(data.(int), Height) + // return err + } + return nil +} + +func (c *CustomizedClient) StopDevice() error { + // TODO: stop device + // you can use c.ProtocolConfig + err := Cam.Close() + if err != nil { + return err + } + return nil +} diff --git a/mappers/usbcamera-dmi/driver/uilts.go b/mappers/usbcamera-dmi/driver/uilts.go new file mode 100755 index 00000000..0f0e458d --- /dev/null +++ b/mappers/usbcamera-dmi/driver/uilts.go @@ -0,0 +1,60 @@ +package driver + +import ( + "encoding/base64" + "fmt" + "github.com/blackjack/webcam" +) + +func SetControl(controls map[webcam.ControlID]webcam.Control, featureName string, data interface{}) error { + for controlID, control := range controls { + if control.Name == featureName { + err := Cam.SetControl(controlID, int32(data.(int64))) + if err != nil { + return err + } + return nil + } + } + err := fmt.Errorf("set control:%s not found the parament", featureName) + return err +} + +func GetControl(controls map[webcam.ControlID]webcam.Control, featureName string) (int32, error) { + for controlID, control := range controls { + if control.Name == featureName { + value, err := Cam.GetControl(controlID) + if err != nil { + return -1, err + } + return value, nil + } + } + err := fmt.Errorf("get control:%s not found the parament", featureName) + return -1, err +} + +var format webcam.PixelFormat = 0 + +func GetImage(width, height, pixelFormat int) (string, error) { + // 读取摄像头的参数 + if format == 0 { + format_ := webcam.PixelFormat(pixelFormat) + if result, _, _, err := Cam.SetImageFormat(format_, uint32(width), uint32(height)); err != nil { + return "", fmt.Errorf("error setting format:%v", err) + } else { + format = result + } + } + if err := Cam.StartStreaming(); err != nil { + if err.Error() != "Already streaming" { + return "", fmt.Errorf("error starting streaming:%v", err) + } + } + frame, err := Cam.ReadFrame() + if err != nil { + return "", fmt.Errorf("error reading frame:%v", err) + } + result := base64.StdEncoding.EncodeToString(frame) + return result, nil +} diff --git a/mappers/usbcamera-dmi/hack/lib/init.sh b/mappers/usbcamera-dmi/hack/lib/init.sh new file mode 100755 index 00000000..e4f56d73 --- /dev/null +++ b/mappers/usbcamera-dmi/hack/lib/init.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +# Copyright 2020 The KubeEdge Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +set -o errexit +set -o nounset +set -o pipefail + +# The root of the kubeedge +KUBEEDGE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)" + +KUBEEDGE_OUTPUT_SUBPATH="${KUBEEDGE_OUTPUT_SUBPATH:-_output/local}" +KUBEEDGE_OUTPUT="${KUBEEDGE_ROOT}/${KUBEEDGE_OUTPUT_SUBPATH}" +KUBEEDGE_OUTPUT_BINPATH="${KUBEEDGE_OUTPUT}/bin" + +readonly KUBEEDGE_GO_PACKAGE="github.com/kubeedge/mappers-go" + +source "${KUBEEDGE_ROOT}/hack/lib/lint.sh" +source "${KUBEEDGE_ROOT}/hack/lib/util.sh" diff --git a/mappers/usbcamera-dmi/hack/lib/install.sh b/mappers/usbcamera-dmi/hack/lib/install.sh new file mode 100755 index 00000000..27e1785b --- /dev/null +++ b/mappers/usbcamera-dmi/hack/lib/install.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash + +# Copyright 2019 The KubeEdge Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# check if kubectl installed +function check_kubectl { + echo "checking kubectl" + command -v kubectl >/dev/null 2>&1 + if [[ $? -ne 0 ]]; then + echo "kubectl not installed, exiting." + exit 1 + else + echo -n "found kubectl, " && kubectl version --short --client + fi +} + +# check if kind installed +function check_kind { + echo "checking kind" + command -v kind >/dev/null 2>&1 + if [[ $? -ne 0 ]]; then + echo "installing kind ." + GO111MODULE="on" go get sigs.k8s.io/kind@v0.9.0 + if [[ $? -ne 0 ]]; then + echo "kind installed failed, exiting." + exit 1 + fi + + # avoid modifing go.sum and go.mod when installing the kind + git checkout -- go.mod go.sum + + export PATH=$PATH:$GOPATH/bin + else + echo -n "found kind, version: " && kind version + fi +} + +# check if golangci-lint installed +function check_golangci-lint { + echo "checking golangci-lint" + command -v golangci-lint >/dev/null 2>&1 + if [[ $? -ne 0 ]]; then + echo "installing golangci-lint ." + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.39.0 + if [[ $? -ne 0 ]]; then + echo "golangci-lint installed failed, exiting." + exit 1 + fi + + export PATH=$PATH:$GOPATH/bin + else + echo -n "found golangci-lint, version: " && golangci-lint version + fi +} + +verify_go_version(){ + if [[ -z "$(command -v go)" ]]; then + echo "Can't find 'go' in PATH, please fix and retry. +See http://golang.org/doc/install for installation instructions." + exit 1 + fi + + local go_version + IFS=" " read -ra go_version <<< "$(go version)" + local minimum_go_version + minimum_go_version=go1.12.1 + if [[ "${minimum_go_version}" != $(echo -e "${minimum_go_version}\n${go_version[2]}" | sort -s -t. -k 1,1 -k 2,2n -k 3,3n | head -n1) && "${go_version[2]}" != "devel" ]]; then + echo "Detected go version: ${go_version[*]}. +Kubernetes requires ${minimum_go_version} or greater. +Please install ${minimum_go_version} or later." + exit 1 + fi +} + +verify_docker_installed(){ + # verify the docker installed + command -v docker >/dev/null || { + echo "must install the docker first" + exit 1 + } +} + diff --git a/mappers/usbcamera-dmi/hack/lib/lint.sh b/mappers/usbcamera-dmi/hack/lib/lint.sh new file mode 100755 index 00000000..cdf3a3f9 --- /dev/null +++ b/mappers/usbcamera-dmi/hack/lib/lint.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash + +### +#Copyright 2020 The KubeEdge Authors. +# +#Licensed under the Apache License, Version 2.0 (the "License"); +#you may not use this file except in compliance with the License. +#You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +#Unless required by applicable law or agreed to in writing, software +#distributed under the License is distributed on an "AS IS" BASIS, +#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#See the License for the specific language governing permissions and +#limitations under the License. +### + +set -o errexit +set -o nounset +set -o pipefail + +SED_CMD="" + +if [[ "$OSTYPE" == "darwin"* ]] +then + SED_CMD=`which gsed` + if [ -z $SED_CMD ] + then + echo "Please install gnu-sed (brew install gnu-sed)" + exit 1 + fi +elif [[ "$OSTYPE" == "linux"* ]] +then + SED_CMD=`which sed` + if [ -z $SED_CMD ] + then + echo "Please install sed" + exit 1 + fi +else + echo "Unsupported OS $OSTYPE" + exit 1 +fi + +kubeedge::lint::check() { + cd ${KUBEEDGE_ROOT} + echo "start lint ..." + set +o pipefail + echo "check any whitenoise ..." + # skip deleted files + if [[ "$OSTYPE" == "darwin"* ]] + then + git diff --cached --name-only --diff-filter=ACRMTU main | grep -Ev "externalversions|fake|vendor|images|adopters" | xargs $SED_CMD -i 's/[ \t]*$//' + elif [[ "$OSTYPE" == "linux"* ]] + then + git diff --cached --name-only --diff-filter=ACRMTU main | grep -Ev "externalversions|fake|vendor|images|adopters" | xargs --no-run-if-empty $SED_CMD -i 's/[ \t]*$//' + else + echo "Unsupported OS $OSTYPE" + exit 1 + fi + + [[ $(git diff --name-only) ]] && { + echo "Some files have white noise issue, please run \`make lint\` to slove this issue" + return 1 + } + set -o pipefail + + echo "check any issue by golangci-lint ..." + GOOS="linux" golangci-lint run -v +} diff --git a/mappers/usbcamera-dmi/hack/lib/util.sh b/mappers/usbcamera-dmi/hack/lib/util.sh new file mode 100755 index 00000000..3d73ab47 --- /dev/null +++ b/mappers/usbcamera-dmi/hack/lib/util.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash + +# Copyright 2014 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ----------------------------------------------------------------------------- +# CHANGELOG +# KubeEdge Authors: +# Some functions derived from https://github.com/kubernetes/kubernetes/blob/v1.19.0-beta.2/hack/utils.sh +# for update-vendor-licenses, verify-vendor-licenses + + +# Example: kube::util::trap_add 'echo "in trap DEBUG"' DEBUG +# See: http://stackoverflow.com/questions/3338030/multiple-bash-traps-for-the-same-signal +kube::util::trap_add() { + local trap_add_cmd + trap_add_cmd=$1 + shift + + for trap_add_name in "$@"; do + local existing_cmd + local new_cmd + + # Grab the currently defined trap commands for this trap + existing_cmd=$(trap -p "${trap_add_name}" | awk -F"'" '{print $2}') + + if [[ -z "${existing_cmd}" ]]; then + new_cmd="${trap_add_cmd}" + else + new_cmd="${trap_add_cmd};${existing_cmd}" + fi + + # Assign the test. Disable the shellcheck warning telling that trap + # commands should be single quoted to avoid evaluating them at this + # point instead evaluating them at run time. The logic of adding new + # commands to a single trap requires them to be evaluated right away. + # shellcheck disable=SC2064 + trap "${new_cmd}" "${trap_add_name}" + done +} + +# Opposite of kube::util::ensure-temp-dir() +kube::util::cleanup-temp-dir() { + rm -rf "${KUBE_TEMP}" +} + +# Create a temp dir that'll be deleted at the end of this bash session. +# +# Vars set: +# KUBE_TEMP +kube::util::ensure-temp-dir() { + if [[ -z ${KUBE_TEMP-} ]]; then + KUBE_TEMP=$(mktemp -d 2>/dev/null || mktemp -d -t kubernetes.XXXXXX) + kube::util::trap_add kube::util::cleanup-temp-dir EXIT + fi +} + +# outputs md5 hash of $1, works on macOS and Linux +function kube::util::md5() { + if which md5 >/dev/null 2>&1; then + md5 -q "$1" + else + md5sum "$1" | awk '{ print $1 }' + fi +} diff --git a/mappers/usbcamera-dmi/hack/make-rules/mapper.sh b/mappers/usbcamera-dmi/hack/make-rules/mapper.sh new file mode 100755 index 00000000..1ead2a90 --- /dev/null +++ b/mappers/usbcamera-dmi/hack/make-rules/mapper.sh @@ -0,0 +1,159 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +CURR_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)" +ROOT_DIR="$(cd "${CURR_DIR}" && pwd -P)" +source "${ROOT_DIR}/hack/lib/init.sh" + +mkdir -p "${CURR_DIR}/bin" +mkdir -p "${CURR_DIR}/dist" + +function mod() { + [[ "${2:-}" != "only" ]] + local mapper="${1}" + + # the mapper is sharing the vendor with root + pushd "${ROOT_DIR}" >/dev/null || exist 1 + echo "downloading dependencies for mapper ${mapper}..." + + if [[ "$(go env GO111MODULE)" == "off" ]]; then + echo "go mod has been disabled by GO111MODULE=off" + else + echo "tidying" + go mod tidy + echo "vending" + go mod vendor + fi + + echo "...done" + popd >/dev/null || return +} + +function lint() { + [[ "${2:-}" != "only" ]] && mod "$@" + local mapper="${1}" + + echo "fmt and linting mapper ${mapper}..." + + gofmt -s -w "${CURR_DIR}/" + #golangci-lint run "${CURR_DIR}/..." + + echo "...done" +} + +function build() { + [[ "${2:-}" != "only" ]] && lint "$@" + local mapper="${1}" + + local flags=" " + local ext_flags=" -extldflags '-static' " + local os="${OS:-$(go env GOOS)}" + local arch="${ARCH:-$(go env GOARCH)}" + + local platform + if [[ "${ARM:-false}" == "true" ]]; then + echo "crossed packaging for linux/arm" + platform=("linux/arm") + elif [[ "${ARM64:-false}" == "true" ]]; then + echo "crossed packaging for linux/arm64" + platform=("linux/arm64") + else + local os="${OS:-$(go env GOOS)}" + local arch="${ARCH:-$(go env GOARCH)}" + platform=("${os}/${arch}") + fi + + echo "building ${platform}" + + local os_arch + IFS="/" read -r -a os_arch <<<"${platform}" + local os=${os_arch[0]} + local arch=${os_arch[1]} + GOOS=${os} GOARCH=${arch} CGO_ENABLED=0 go build \ + -ldflags "${flags} ${ext_flags}" \ + -o "${CURR_DIR}/bin/${mapper}_${os}_${arch}" \ + "${CURR_DIR}/cmd/main.go" + + cp ${CURR_DIR}/bin/${mapper}_${os}_${arch} ${CURR_DIR}/bin/${mapper} + echo "...done" +} + +function package() { + [[ "${2:-}" != "only" ]] && build "$@" + local mapper="${1}" + + echo "packaging mapper ${mapper}..." + + local image_name="${mapper}-mapper" + local tag=v1.0 + + local platform + if [[ "${ARM:-false}" == "true" ]]; then + echo "crossed packaging for linux/arm" + platform=("linux/arm") + elif [[ "${ARM64:-false}" == "true" ]]; then + echo "crossed packaging for linux/arm64" + platform=("linux/arm64") + else + local os="${OS:-$(go env GOOS)}" + local arch="${ARCH:-$(go env GOARCH)}" + platform=("${os}/${arch}") + fi + + pushd "${CURR_DIR}" >/dev/null 2>&1 + if [[ "${platform}" =~ darwin/* ]]; then + echo "package into Darwin OS image is unavailable, please use CROSS=true env to containerize multiple arch images or use OS=linux ARCH=amd64 env to containerize linux/amd64 image" + fi + + local image_tag="${image_name}:${tag}-${platform////-}" + echo "packaging ${image_tag}" + sudo docker build \ + --platform "${platform}" \ + -t "${image_tag}" . + popd >/dev/null 2>&1 + + echo "...done" +} + +function clean() { + local mapper="${1}" + + echo "cleanup mapper ${mapper}..." + + rm -rf "${CURR_DIR}/bin/*" + + echo "...done" +} + +function entry() { + local mapper="${1:-}" + shift 1 + + local stages="${1:-build}" + shift $(($# > 0 ? 1 : 0)) + + IFS="," read -r -a stages <<<"${stages}" + local commands=$* + if [[ ${#stages[@]} -ne 1 ]]; then + commands="only" + fi + + for stage in "${stages[@]}"; do + echo "# make mapper ${mapper} ${stage} ${commands}" + case ${stage} in + m | mod) mod "${mapper}" "${commands}" ;; + l | lint) lint "${mapper}" "${commands}" ;; + b | build) build "${mapper}" "${commands}" ;; + p | pkg | package) package "${mapper}" "${commands}" ;; + t | test) test "${mapper}" "${commands}" ;; + c | clean) clean "${mapper}" "${commands}" ;; + *) echo "unknown action '${stage}', select from mod,lint,build,test,clean" ;; + esac + done +} + +echo $@ +entry "$@" diff --git a/mappers/usbcamera-dmi/pkg/common/configmaptype.go b/mappers/usbcamera-dmi/pkg/common/configmaptype.go new file mode 100755 index 00000000..0e8e756e --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/common/configmaptype.go @@ -0,0 +1,122 @@ +/* +Copyright 2023 The KubeEdge Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import "encoding/json" + +// DeviceProfile is structure to store in configMap. It will be removed later +type DeviceProfile struct { + DeviceInstances []DeviceInstance `json:"deviceInstances,omitempty"` + DeviceModels []DeviceModel `json:"deviceModels,omitempty"` + Protocols []ProtocolConfig `json:"protocols,omitempty"` +} + +// DeviceInstance is structure to store device in deviceProfile.json in configmap. +type DeviceInstance struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + ProtocolName string `json:"protocol,omitempty"` + PProtocol ProtocolConfig + Model string `json:"model,omitempty"` + Twins []Twin `json:"twins,omitempty"` + Properties []DeviceProperty `json:"properties,omitempty"` +} + +// DeviceModel is structure to store deviceModel in deviceProfile.json in configmap. +type DeviceModel struct { + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Properties []ModelProperty `json:"properties,omitempty"` +} + +// ModelProperty is structure to store deviceModel property. +type ModelProperty struct { + Name string `json:"name,omitempty"` + DataType string `json:"dataType,omitempty"` + Description string `json:"description,omitempty"` + AccessMode string `json:"accessMode,omitempty"` + Minimum string `json:"minimum,omitempty"` + Maximum string `json:"maximum,omitempty"` + Unit string `json:"unit,omitempty"` +} + +// Protocol is structure to store protocol in deviceProfile.json in configmap. + +type ProtocolConfig struct { + // Unique protocol name + // Required. + ProtocolName string `json:"protocolName,omitempty"` + // Any config data + // +optional + // +kubebuilder:validation:XPreserveUnknownFields + ConfigData json.RawMessage `json:"configData,omitempty"` +} + +// DeviceProperty is structure to store propertyVisitor in deviceProfile.json in configmap. +type DeviceProperty struct { + Name string `json:"name,omitempty"` + PropertyName string `json:"propertyName,omitempty"` + ModelName string `json:"modelName,omitempty"` + Protocol string `json:"protocol,omitempty"` + Visitors json.RawMessage `json:"visitorConfig"` + // whether be reported to the cloud + ReportToCloud bool `json:"reportToCloud,omitempty"` + CollectCycle int64 `json:"collectCycle"` + ReportCycle int64 `json:"reportCycle,omitempty"` + PushMethod PushMethodConfig `json:"pushMethod,omitempty"` + PProperty ModelProperty +} + +// PushMethodConfig is structure to store push config +type PushMethodConfig struct { + MethodName string `json:"MethodName"` + MethodConfig json.RawMessage `json:"MethodConfig"` + DBMethod DBMethodConfig `json:"dbMethod,omitempty"` +} + +type DBMethodConfig struct { + DBMethodName string `json:"dbMethodName"` + DBConfig DBConfig `json:"dbConfig"` +} + +type DBConfig struct { + Influxdb2ClientConfig json.RawMessage `json:"influxdb2ClientConfig"` + Influxdb2DataConfig json.RawMessage `json:"influxdb2DataConfig"` + RedisConfigData json.RawMessage `json:"redisConfigData"` +} + +// Metadata is the metadata for data. +type Metadata struct { + Timestamp string `json:"timestamp,omitempty"` + Type string `json:"type,omitempty"` +} + +// Twin is the set/get pair to one register. +type Twin struct { + PropertyName string `json:"propertyName,omitempty"` + Property *DeviceProperty + ObservedDesired TwinProperty `json:"observedDesired,omitempty"` + Reported TwinProperty `json:"reported,omitempty"` +} + +type TwinProperty struct { + // Required: The value for this property. + Value string `json:"value,"` + // Additional metadata like timestamp when the value was reported etc. + // +optional + Metadata Metadata `json:"metadata,omitempty"` +} diff --git a/mappers/usbcamera-dmi/pkg/common/const.go b/mappers/usbcamera-dmi/pkg/common/const.go new file mode 100755 index 00000000..8daf3811 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/common/const.go @@ -0,0 +1,43 @@ +/* +Copyright 2023 The KubeEdge Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import "time" + +// Device status definition. +const ( + DEVSTOK = "OK" + DEVSTERR = "ERROR" /* Expected value is not equal as setting */ + DEVSTDISCONN = "DISCONNECTED" /* Disconnected */ + DEVSTUNHEALTHY = "UNHEALTHY" /* Unhealthy status from device */ + DEVSTUNKNOWN = "UNKNOWN" +) +const ( + ProtocolBlueTooth = "bluetooth" + ProtocolModbus = "modbus" + ProtocolOnvif = "onvif" + ProtocolOpcua = "opcua" + ProtocolCustomized = "customized-protocol" +) + +const DefaultCollectCycle = time.Second +const DefaultReportCycle = time.Second + +const ( + DevInitModeRegister = "register" + DevInitModeConfigmap = "configmap" +) diff --git a/mappers/usbcamera-dmi/pkg/common/dataconverter.go b/mappers/usbcamera-dmi/pkg/common/dataconverter.go new file mode 100755 index 00000000..f1c8c854 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/common/dataconverter.go @@ -0,0 +1,169 @@ +/* +Copyright 2023 The KubeEdge Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import ( + "encoding/json" + "errors" + "fmt" + "reflect" + "strconv" + "strings" + + "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/wrapperspb" +) + +// Convert string to other types +func Convert(valueType string, value string) (result interface{}, err error) { + switch valueType { + case "int": + return strconv.ParseInt(value, 10, 64) + case "float": + return strconv.ParseFloat(value, 32) + case "double": + return strconv.ParseFloat(value, 64) + case "boolean": + return strconv.ParseBool(value) + case "string": + return value, nil + default: + return nil, errors.New("Convert failed") + } +} + +// ConvertToString other types to string +func ConvertToString(value interface{}) (string, error) { + var result string + if value == nil { + return result, nil + } + switch v := value.(type) { + case float64: + ft := v + result = strconv.FormatFloat(ft, 'f', -1, 64) + case float32: + ft := v + result = strconv.FormatFloat(float64(ft), 'f', -1, 64) + case int: + it := v + result = strconv.Itoa(it) + case uint: + it := v + result = strconv.Itoa(int(it)) + case int8: + it := v + result = strconv.Itoa(int(it)) + case uint8: + it := v + result = strconv.Itoa(int(it)) + case int16: + it := v + result = strconv.Itoa(int(it)) + case uint16: + it := v + result = strconv.Itoa(int(it)) + case int32: + it := v + result = strconv.Itoa(int(it)) + case uint32: + it := v + result = strconv.Itoa(int(it)) + case int64: + it := v + result = strconv.FormatInt(it, 10) + case uint64: + it := v + result = strconv.FormatUint(it, 10) + case string: + result = v + case []byte: + result = string(v) + default: + newValue, err := json.Marshal(value) + if err != nil { + return "", err + } + result = string(newValue) + } + return result, nil +} + +// DecodeAnyValue Any to interface +func DecodeAnyValue(value *anypb.Any) (interface{}, error) { + typeURL := value.GetTypeUrl() + + messageTypeName := getMessageTypeName(typeURL) + if messageTypeName == "" { + return nil, fmt.Errorf("cant get message type:%s", typeURL) + } + if strings.Contains(messageTypeName, "google.protobuf.") { + switch messageTypeName { + case "google.protobuf.Int32Value": + return decodeWrapperValue(value, &wrapperspb.Int32Value{}) + case "google.protobuf.StringValue": + return decodeWrapperValue(value, &wrapperspb.StringValue{}) + case "google.protobuf.FloatValue": + return decodeWrapperValue(value, &wrapperspb.FloatValue{}) + case "google.protobuf.BoolValue": + return decodeWrapperValue(value, &wrapperspb.BoolValue{}) + case "google.protobuf.Int64Value": + return decodeWrapperValue(value, &wrapperspb.Int64Value{}) + default: + return nil, fmt.Errorf("unknown type : %s", messageTypeName) + } + } + messageType := proto.MessageType(messageTypeName) + if messageType == nil { + return nil, fmt.Errorf("cant get message type:%s", messageTypeName) + } + + if !reflect.TypeOf((*proto.Message)(nil)).Elem().AssignableTo(messageType) { + return nil, fmt.Errorf("assiganbleto proto.Message error:%s", messageTypeName) + } + message := reflect.New(messageType.Elem()).Interface().(proto.Message) + if err := proto.Unmarshal(value.Value, message); err != nil { + return nil, fmt.Errorf("unmarshal value error:%v", err) + } + return message, nil +} + +// decodeWrapperValue get proto.Message, then convert to interface +func decodeWrapperValue(value *anypb.Any, wrapper proto.Message) (interface{}, error) { + if err := proto.Unmarshal(value.Value, wrapper); err != nil { + return nil, fmt.Errorf("decode wrapperValue,proto unmarshal error:%v", err) + } + wrapperValue := reflect.ValueOf(wrapper).Elem() + valueField := wrapperValue.FieldByName("Value") + if !valueField.IsValid() { + return nil, fmt.Errorf("cant get wrapperValue") + } + return valueField.Interface(), nil +} + +// getMessageTypeName get type by parse type url +func getMessageTypeName(typeURL string) string { + index := len(typeURL) - 1 + for index >= 0 && typeURL[index] != '/' { + index-- + } + if index >= 0 && index < len(typeURL)-1 { + return typeURL[index+1:] + } + return "" +} diff --git a/mappers/usbcamera-dmi/pkg/common/datamodel.go b/mappers/usbcamera-dmi/pkg/common/datamodel.go new file mode 100755 index 00000000..effd2739 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/common/datamodel.go @@ -0,0 +1,57 @@ +package common + +// DataModel defined standard data model for transferring data between interfaces +type DataModel struct { + // TODO DataModel is standardized data, need add field + DeviceName string + PropertyName string + + Value string + Type string + + TimeStamp int64 +} + +type Option func(*DataModel) + +func (dm *DataModel) SetType(dataType string) { + dm.Type = dataType +} + +func (dm *DataModel) SetValue(data string) { + dm.Value = data +} + +func (dm *DataModel) SetTimeStamp() { + dm.TimeStamp = getTimestamp() +} + +func WithType(dataType string) Option { + return func(model *DataModel) { + model.Type = dataType + } +} + +func WithValue(data string) Option { + return func(model *DataModel) { + model.Value = data + } +} + +func WithTimeStamp(timeStamp int64) Option { + return func(model *DataModel) { + model.TimeStamp = timeStamp + } +} + +func NewDataModel(deviceName string, propertyName string, options ...Option) *DataModel { + dataModel := &DataModel{ + DeviceName: deviceName, + PropertyName: propertyName, + TimeStamp: getTimestamp(), + } + for _, option := range options { + option(dataModel) + } + return dataModel +} diff --git a/mappers/usbcamera-dmi/pkg/common/event.go b/mappers/usbcamera-dmi/pkg/common/event.go new file mode 100755 index 00000000..9820ecd9 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/common/event.go @@ -0,0 +1,65 @@ +/* +Copyright 2023 The KubeEdge Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import ( + "encoding/json" + "time" +) + +// Joint the topic like topic := fmt.Sprintf(TopicTwinUpdateDelta, deviceID) +const ( + TopicTwinUpdateDelta = "$hw/events/device/%s/twin/update/delta" + TopicTwinUpdate = "$hw/events/device/%s/twin/update" + TopicStateUpdate = "$hw/events/device/%s/state/update" + TopicDataUpdate = "$ke/events/device/%s/data/update" +) + +// getTimestamp get current timestamp. +func getTimestamp() int64 { + return time.Now().UnixNano() / 1e6 +} + +// CreateMessageTwinUpdate create twin update message. +func CreateMessageTwinUpdate(name string, valueType string, value string, expectValue string) (msg []byte, err error) { + var updateMsg DeviceTwinUpdate + + updateMsg.BaseMessage.Timestamp = getTimestamp() + updateMsg.Twin = map[string]*MsgTwin{} + updateMsg.Twin[name] = &MsgTwin{} + updateMsg.Twin[name].Actual = &TwinValue{Value: &value} + updateMsg.Twin[name].Expected = &TwinValue{Value: &expectValue} + updateMsg.Twin[name].Metadata = &TypeMetadata{Type: valueType} + + msg, err = json.Marshal(updateMsg) + return +} + +// CreateMessageData create data message. +func CreateMessageData(name string, valueType string, value string) (msg []byte, err error) { + var dataMsg DeviceData + + dataMsg.BaseMessage.Timestamp = getTimestamp() + dataMsg.Data = map[string]*DataValue{} + dataMsg.Data[name] = &DataValue{} + dataMsg.Data[name].Value = value + dataMsg.Data[name].Metadata.Type = valueType + dataMsg.Data[name].Metadata.Timestamp = getTimestamp() + + msg, err = json.Marshal(dataMsg) + return +} diff --git a/mappers/usbcamera-dmi/pkg/common/eventtype.go b/mappers/usbcamera-dmi/pkg/common/eventtype.go new file mode 100755 index 00000000..cf9fe8b3 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/common/eventtype.go @@ -0,0 +1,106 @@ +/* +Copyright 2023 The KubeEdge Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +// BaseMessage the base structure of event message. +type BaseMessage struct { + EventID string `json:"event_id"` + Timestamp int64 `json:"timestamp"` +} + +// TwinValue the structure of twin value. +type TwinValue struct { + Value *string `json:"value,omitempty"` + Metadata ValueMetadata `json:"metadata,omitempty"` +} + +// ValueMetadata the meta of value. +type ValueMetadata struct { + Timestamp string `json:"timestamp,omitempty"` +} + +// TypeMetadata the meta of value type. +type TypeMetadata struct { + Type string `json:"type,omitempty"` +} + +// TwinVersion twin version. +type TwinVersion struct { + CloudVersion int64 `json:"cloud"` + EdgeVersion int64 `json:"edge"` +} + +// MsgTwin the structure of device twin. +type MsgTwin struct { + Expected *TwinValue `json:"expected,omitempty"` + Actual *TwinValue `json:"actual,omitempty"` + Optional *bool `json:"optional,omitempty"` + Metadata *TypeMetadata `json:"metadata,omitempty"` + ExpectedVersion *TwinVersion `json:"expected_version,omitempty"` + ActualVersion *TwinVersion `json:"actual_version,omitempty"` +} + +// DeviceTwinUpdate the structure of device twin update. +type DeviceTwinUpdate struct { + BaseMessage + Twin map[string]*MsgTwin `json:"twin"` +} + +// DeviceTwinResult device get result. +type DeviceTwinResult struct { + BaseMessage + Twin map[string]*MsgTwin `json:"twin"` +} + +// DeviceTwinDelta twin delta. +type DeviceTwinDelta struct { + BaseMessage + Twin map[string]*MsgTwin `json:"twin"` + Delta map[string]string `json:"delta"` +} + +// DataMetadata data metadata. +type DataMetadata struct { + Timestamp int64 `json:"timestamp"` + Type string `json:"type"` +} + +// DataValue data value. +type DataValue struct { + Value string `json:"value"` + Metadata DataMetadata `json:"metadata"` +} + +// DeviceData device data structure. +type DeviceData struct { + BaseMessage + Data map[string]*DataValue `json:"data"` +} + +// MsgAttr the struct of device attr +type MsgAttr struct { + Value string `json:"value"` + Optional *bool `json:"optional,omitempty"` + Metadata *TypeMetadata `json:"metadata,omitempty"` +} + +// DeviceUpdate device update. +type DeviceUpdate struct { + BaseMessage + State string `json:"state,omitempty"` + Attributes map[string]*MsgAttr `json:"attributes"` +} diff --git a/mappers/usbcamera-dmi/pkg/config/config.go b/mappers/usbcamera-dmi/pkg/config/config.go new file mode 100755 index 00000000..3d438c7d --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/config/config.go @@ -0,0 +1,99 @@ +/* +Copyright 2023 The KubeEdge Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + "errors" + "io/ioutil" + "os" + "strings" + + "github.com/spf13/pflag" + "gopkg.in/yaml.v2" + "k8s.io/klog/v2" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" +) + +var defaultConfigFile = "./config.yaml" + +// Config is the common mapper configuration. +type Config struct { + GrpcServer GRPCServer `yaml:"grpc_server"` + Common Common `yaml:"common"` + DevInit DevInit `yaml:"dev_init"` +} + +type GRPCServer struct { + SocketPath string `yaml:"socket_path"` +} + +type Common struct { + Name string `yaml:"name"` + Version string `yaml:"version"` + APIVersion string `yaml:"api_version"` + Protocol string `yaml:"protocol"` + Address string `yaml:"address"` + EdgeCoreSock string `yaml:"edgecore_sock"` +} + +type DevInit struct { + Mode string `yaml:"mode"` + Configmap string `yaml:"configmap"` +} + +// Parse the configuration file. If failed, return error. +func (c *Config) Parse() error { + var level klog.Level + var loglevel string + var configFile string + + pflag.StringVar(&loglevel, "v", "1", "log level") + pflag.StringVar(&configFile, "config-file", defaultConfigFile, "Config file name") + pflag.Parse() + cf, err := ioutil.ReadFile(configFile) + if err != nil { + return err + } + if err = yaml.Unmarshal(cf, c); err != nil { + return err + } + if err = level.Set(loglevel); err != nil { + return err + } + + switch c.DevInit.Mode { + case common.DevInitModeConfigmap: + if _, err := ioutil.ReadFile(c.DevInit.Configmap); err != nil { + if !os.IsNotExist(err) { + return err + } + c.DevInit.Configmap = strings.TrimSpace(os.Getenv("DEVICE_PROFILE")) + } + if strings.TrimSpace(c.DevInit.Configmap) == "" { + return errors.New("can not parse configmap") + } + case common.DevInitModeRegister: + case "": // if mode is nil, use meta server mode + c.DevInit.Mode = common.DevInitModeRegister + fallthrough + default: + return errors.New("unsupported dev init mode " + c.DevInit.Mode) + } + + return nil +} diff --git a/mappers/usbcamera-dmi/pkg/dmi-api/api.pb.go b/mappers/usbcamera-dmi/pkg/dmi-api/api.pb.go new file mode 100755 index 00000000..19e252db --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/dmi-api/api.pb.go @@ -0,0 +1,3242 @@ +/* +Copyright 2022 The KubeEdge Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// +// To regenerate api.pb.go run hack/generate-dmi.sh + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.19.4 +// source: api.proto + +package v1beta1 + +import ( + "google.golang.org/grpc" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + anypb "google.golang.org/protobuf/types/known/anypb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type MapperRegisterRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The flag to show how device manager returns. + // True means device manager should return the device list in the response. + // False means device manager should just return nothing. + WithData bool `protobuf:"varint,1,opt,name=withData,proto3" json:"withData,omitempty"` + // Mapper information to be registered to the device manager. + Mapper *MapperInfo `protobuf:"bytes,2,opt,name=mapper,proto3" json:"mapper,omitempty"` +} + +func (x *MapperRegisterRequest) Reset() { + *x = MapperRegisterRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MapperRegisterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MapperRegisterRequest) ProtoMessage() {} + +func (x *MapperRegisterRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MapperRegisterRequest.ProtoReflect.Descriptor instead. +func (*MapperRegisterRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{0} +} + +func (x *MapperRegisterRequest) GetWithData() bool { + if x != nil { + return x.WithData + } + return false +} + +func (x *MapperRegisterRequest) GetMapper() *MapperInfo { + if x != nil { + return x.Mapper + } + return nil +} + +type MapperRegisterResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // List of device models which the mapper maintains. + ModelList []*DeviceModel `protobuf:"bytes,1,rep,name=modelList,proto3" json:"modelList,omitempty"` + // List of devices which the mapper maintains. + DeviceList []*Device `protobuf:"bytes,2,rep,name=deviceList,proto3" json:"deviceList,omitempty"` +} + +func (x *MapperRegisterResponse) Reset() { + *x = MapperRegisterResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MapperRegisterResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MapperRegisterResponse) ProtoMessage() {} + +func (x *MapperRegisterResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MapperRegisterResponse.ProtoReflect.Descriptor instead. +func (*MapperRegisterResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{1} +} + +func (x *MapperRegisterResponse) GetModelList() []*DeviceModel { + if x != nil { + return x.ModelList + } + return nil +} + +func (x *MapperRegisterResponse) GetDeviceList() []*Device { + if x != nil { + return x.DeviceList + } + return nil +} + +// DeviceModel specifies the information of a device model. +type DeviceModel struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Name of a device model. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Specification of a device model. + Spec *DeviceModelSpec `protobuf:"bytes,2,opt,name=spec,proto3" json:"spec,omitempty"` +} + +func (x *DeviceModel) Reset() { + *x = DeviceModel{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeviceModel) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeviceModel) ProtoMessage() {} + +func (x *DeviceModel) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeviceModel.ProtoReflect.Descriptor instead. +func (*DeviceModel) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{2} +} + +func (x *DeviceModel) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *DeviceModel) GetSpec() *DeviceModelSpec { + if x != nil { + return x.Spec + } + return nil +} + +// DeviceModelSpec is the specification of a device model. +type DeviceModelSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The properties provided by the device of this device model. + Properties []*ModelProperty `protobuf:"bytes,1,rep,name=properties,proto3" json:"properties,omitempty"` + // The commands executed by the device of this device model. + Commands []*DeviceCommand `protobuf:"bytes,2,rep,name=commands,proto3" json:"commands,omitempty"` +} + +func (x *DeviceModelSpec) Reset() { + *x = DeviceModelSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeviceModelSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeviceModelSpec) ProtoMessage() {} + +func (x *DeviceModelSpec) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeviceModelSpec.ProtoReflect.Descriptor instead. +func (*DeviceModelSpec) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{3} +} + +func (x *DeviceModelSpec) GetProperties() []*ModelProperty { + if x != nil { + return x.Properties + } + return nil +} + +func (x *DeviceModelSpec) GetCommands() []*DeviceCommand { + if x != nil { + return x.Commands + } + return nil +} + +// ModelProperty is the property of a device. +type ModelProperty struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of this property. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The description of this property. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // The specific type of this property. + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + // The access mode of this property, ReadOnly or ReadWrite. + AccessMode string `protobuf:"bytes,4,opt,name=accessMode,proto3" json:"accessMode,omitempty"` + // The minimum value of this property. + Minimum string `protobuf:"bytes,5,opt,name=minimum,proto3" json:"minimum,omitempty"` + // The maximum value of this property. + Maximum string `protobuf:"bytes,6,opt,name=maximum,proto3" json:"maximum,omitempty"` + // The unit of this property. + Unit string `protobuf:"bytes,7,opt,name=unit,proto3" json:"unit,omitempty"` +} + +func (x *ModelProperty) Reset() { + *x = ModelProperty{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ModelProperty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ModelProperty) ProtoMessage() {} + +func (x *ModelProperty) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ModelProperty.ProtoReflect.Descriptor instead. +func (*ModelProperty) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{4} +} + +func (x *ModelProperty) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ModelProperty) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *ModelProperty) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *ModelProperty) GetAccessMode() string { + if x != nil { + return x.AccessMode + } + return "" +} + +func (x *ModelProperty) GetMinimum() string { + if x != nil { + return x.Minimum + } + return "" +} + +func (x *ModelProperty) GetMaximum() string { + if x != nil { + return x.Maximum + } + return "" +} + +func (x *ModelProperty) GetUnit() string { + if x != nil { + return x.Unit + } + return "" +} + +// DeviceCommond is the description of a command which the device supports. +type DeviceCommand struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Name of the command. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Url of the command to access. + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + // Method of the command. + Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"` + // Status code list which the command can return. + StatusCode []string `protobuf:"bytes,4,rep,name=status_code,json=statusCode,proto3" json:"status_code,omitempty"` + // Parameter list which the command carries. + Parameters []string `protobuf:"bytes,5,rep,name=parameters,proto3" json:"parameters,omitempty"` + // Response examples of the command. + Response []byte `protobuf:"bytes,6,opt,name=response,proto3" json:"response,omitempty"` +} + +func (x *DeviceCommand) Reset() { + *x = DeviceCommand{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeviceCommand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeviceCommand) ProtoMessage() {} + +func (x *DeviceCommand) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeviceCommand.ProtoReflect.Descriptor instead. +func (*DeviceCommand) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{5} +} + +func (x *DeviceCommand) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *DeviceCommand) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *DeviceCommand) GetMethod() string { + if x != nil { + return x.Method + } + return "" +} + +func (x *DeviceCommand) GetStatusCode() []string { + if x != nil { + return x.StatusCode + } + return nil +} + +func (x *DeviceCommand) GetParameters() []string { + if x != nil { + return x.Parameters + } + return nil +} + +func (x *DeviceCommand) GetResponse() []byte { + if x != nil { + return x.Response + } + return nil +} + +// Device is the description of a device instance. +type Device struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Name of the device. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Specification of the device. + Spec *DeviceSpec `protobuf:"bytes,2,opt,name=spec,proto3" json:"spec,omitempty"` + // Status of the device. + Status *DeviceStatus `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` +} + +func (x *Device) Reset() { + *x = Device{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Device) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Device) ProtoMessage() {} + +func (x *Device) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Device.ProtoReflect.Descriptor instead. +func (*Device) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{6} +} + +func (x *Device) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Device) GetSpec() *DeviceSpec { + if x != nil { + return x.Spec + } + return nil +} + +func (x *Device) GetStatus() *DeviceStatus { + if x != nil { + return x.Status + } + return nil +} + +// DeviceSpec is the specification of the device. +type DeviceSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The device model which the device references. + DeviceModelReference string `protobuf:"bytes,1,opt,name=deviceModelReference,proto3" json:"deviceModelReference,omitempty"` + // The specific config of the protocol to access to the device. + Protocol *ProtocolConfig `protobuf:"bytes,2,opt,name=protocol,proto3" json:"protocol,omitempty"` + // List of properties which describe the device properties. + Properties []*DeviceProperty `protobuf:"bytes,3,rep,name=properties,proto3" json:"properties,omitempty"` +} + +func (x *DeviceSpec) Reset() { + *x = DeviceSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeviceSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeviceSpec) ProtoMessage() {} + +func (x *DeviceSpec) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeviceSpec.ProtoReflect.Descriptor instead. +func (*DeviceSpec) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{7} +} + +func (x *DeviceSpec) GetDeviceModelReference() string { + if x != nil { + return x.DeviceModelReference + } + return "" +} + +func (x *DeviceSpec) GetProtocol() *ProtocolConfig { + if x != nil { + return x.Protocol + } + return nil +} + +func (x *DeviceSpec) GetProperties() []*DeviceProperty { + if x != nil { + return x.Properties + } + return nil +} + +// DeviceProperty describes the specifics all the properties of the device. +type DeviceProperty struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The device property name to be accessed. It must be unique. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // the desired value of the property configured by device manager. + Desired *TwinProperty `protobuf:"bytes,2,opt,name=desired,proto3" json:"desired,omitempty"` + // Visitors are intended to be consumed by device mappers which connect to devices + // and collect data / perform actions on the device. + Visitors *VisitorConfig `protobuf:"bytes,3,opt,name=visitors,proto3" json:"visitors,omitempty"` + // Define how frequent mapper will report the value. + ReportCycle int64 `protobuf:"varint,4,opt,name=reportCycle,proto3" json:"reportCycle,omitempty"` + // Define how frequent mapper will collect from device. + CollectCycle int64 `protobuf:"varint,5,opt,name=collectCycle,proto3" json:"collectCycle,omitempty"` + // whether be reported to the cloud + ReportToCloud bool `protobuf:"varint,6,opt,name=reportToCloud,proto3" json:"reportToCloud,omitempty"` + // PushMethod represents the protocol used to push data, + PushMethod *PushMethod `protobuf:"bytes,7,opt,name=pushMethod,proto3" json:"pushMethod,omitempty"` +} + +func (x *DeviceProperty) Reset() { + *x = DeviceProperty{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeviceProperty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeviceProperty) ProtoMessage() {} + +func (x *DeviceProperty) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeviceProperty.ProtoReflect.Descriptor instead. +func (*DeviceProperty) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{8} +} + +func (x *DeviceProperty) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *DeviceProperty) GetDesired() *TwinProperty { + if x != nil { + return x.Desired + } + return nil +} + +func (x *DeviceProperty) GetVisitors() *VisitorConfig { + if x != nil { + return x.Visitors + } + return nil +} + +func (x *DeviceProperty) GetReportCycle() int64 { + if x != nil { + return x.ReportCycle + } + return 0 +} + +func (x *DeviceProperty) GetCollectCycle() int64 { + if x != nil { + return x.CollectCycle + } + return 0 +} + +func (x *DeviceProperty) GetReportToCloud() bool { + if x != nil { + return x.ReportToCloud + } + return false +} + +func (x *DeviceProperty) GetPushMethod() *PushMethod { + if x != nil { + return x.PushMethod + } + return nil +} + +// ProtocolConfig is the specific config of the protocol to access to the device. +type ProtocolConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // the name of the customized protocol. + ProtocolName string `protobuf:"bytes,1,opt,name=protocolName,proto3" json:"protocolName,omitempty"` + // the config data of the customized protocol. + ConfigData *CustomizedValue `protobuf:"bytes,2,opt,name=configData,proto3" json:"configData,omitempty"` +} + +func (x *ProtocolConfig) Reset() { + *x = ProtocolConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProtocolConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtocolConfig) ProtoMessage() {} + +func (x *ProtocolConfig) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtocolConfig.ProtoReflect.Descriptor instead. +func (*ProtocolConfig) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{9} +} + +func (x *ProtocolConfig) GetProtocolName() string { + if x != nil { + return x.ProtocolName + } + return "" +} + +func (x *ProtocolConfig) GetConfigData() *CustomizedValue { + if x != nil { + return x.ConfigData + } + return nil +} + +// the visitor to collect the properties of the device of customized protocol. +type VisitorConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // the name of the customized protocol. + ProtocolName string `protobuf:"bytes,1,opt,name=protocolName,proto3" json:"protocolName,omitempty"` + // the config data of the customized protocol. + ConfigData *CustomizedValue `protobuf:"bytes,2,opt,name=configData,proto3" json:"configData,omitempty"` +} + +func (x *VisitorConfig) Reset() { + *x = VisitorConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VisitorConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VisitorConfig) ProtoMessage() {} + +func (x *VisitorConfig) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VisitorConfig.ProtoReflect.Descriptor instead. +func (*VisitorConfig) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{10} +} + +func (x *VisitorConfig) GetProtocolName() string { + if x != nil { + return x.ProtocolName + } + return "" +} + +func (x *VisitorConfig) GetConfigData() *CustomizedValue { + if x != nil { + return x.ConfigData + } + return nil +} + +// CustomizedValue is the customized value for developers. +type CustomizedValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // data is the customized value and it can be any form. + Data map[string]*anypb.Any `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *CustomizedValue) Reset() { + *x = CustomizedValue{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CustomizedValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CustomizedValue) ProtoMessage() {} + +func (x *CustomizedValue) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CustomizedValue.ProtoReflect.Descriptor instead. +func (*CustomizedValue) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{11} +} + +func (x *CustomizedValue) GetData() map[string]*anypb.Any { + if x != nil { + return x.Data + } + return nil +} + +type PushMethod struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Http *PushMethodHTTP `protobuf:"bytes,1,opt,name=http,proto3" json:"http,omitempty"` + Mqtt *PushMethodMQTT `protobuf:"bytes,2,opt,name=mqtt,proto3" json:"mqtt,omitempty"` + DBMethod *DBMethod `protobuf:"bytes,3,opt,name=dbMethod,proto3" json:"dbMethod,omitempty"` +} + +func (x *PushMethod) Reset() { + *x = PushMethod{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushMethod) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushMethod) ProtoMessage() {} + +func (x *PushMethod) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushMethod.ProtoReflect.Descriptor instead. +func (*PushMethod) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{12} +} + +func (x *PushMethod) GetHttp() *PushMethodHTTP { + if x != nil { + return x.Http + } + return nil +} + +func (x *PushMethod) GetMqtt() *PushMethodMQTT { + if x != nil { + return x.Mqtt + } + return nil +} + +func (x *PushMethod) GetDBMethod() *DBMethod { + if x != nil { + return x.DBMethod + } + return nil +} + +type PushMethodHTTP struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hostname string `protobuf:"bytes,1,opt,name=hostname,proto3" json:"hostname,omitempty"` + Port int64 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` + Requestpath string `protobuf:"bytes,3,opt,name=requestpath,proto3" json:"requestpath,omitempty"` + Timeout int64 `protobuf:"varint,4,opt,name=timeout,proto3" json:"timeout,omitempty"` +} + +func (x *PushMethodHTTP) Reset() { + *x = PushMethodHTTP{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushMethodHTTP) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushMethodHTTP) ProtoMessage() {} + +func (x *PushMethodHTTP) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushMethodHTTP.ProtoReflect.Descriptor instead. +func (*PushMethodHTTP) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{13} +} + +func (x *PushMethodHTTP) GetHostname() string { + if x != nil { + return x.Hostname + } + return "" +} + +func (x *PushMethodHTTP) GetPort() int64 { + if x != nil { + return x.Port + } + return 0 +} + +func (x *PushMethodHTTP) GetRequestpath() string { + if x != nil { + return x.Requestpath + } + return "" +} + +func (x *PushMethodHTTP) GetTimeout() int64 { + if x != nil { + return x.Timeout + } + return 0 +} + +type PushMethodMQTT struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // broker address, like mqtt://127.0.0.1:1883 + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // publish topic for mqtt + Topic string `protobuf:"bytes,2,opt,name=topic,proto3" json:"topic,omitempty"` + // qos of mqtt publish param + Qos int32 `protobuf:"varint,3,opt,name=qos,proto3" json:"qos,omitempty"` + // Is the message retained + Retained bool `protobuf:"varint,4,opt,name=retained,proto3" json:"retained,omitempty"` +} + +func (x *PushMethodMQTT) Reset() { + *x = PushMethodMQTT{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushMethodMQTT) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushMethodMQTT) ProtoMessage() {} + +func (x *PushMethodMQTT) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushMethodMQTT.ProtoReflect.Descriptor instead. +func (*PushMethodMQTT) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{14} +} + +func (x *PushMethodMQTT) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *PushMethodMQTT) GetTopic() string { + if x != nil { + return x.Topic + } + return "" +} + +func (x *PushMethodMQTT) GetQos() int32 { + if x != nil { + return x.Qos + } + return 0 +} + +func (x *PushMethodMQTT) GetRetained() bool { + if x != nil { + return x.Retained + } + return false +} + +type DBMethod struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // the config of database . + Influxdb2 *DBMethodInfluxdb2 `protobuf:"bytes,1,opt,name=influxdb2,proto3" json:"influxdb2,omitempty"` +} + +func (x *DBMethod) Reset() { + *x = DBMethod{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DBMethod) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DBMethod) ProtoMessage() {} + +func (x *DBMethod) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DBMethod.ProtoReflect.Descriptor instead. +func (*DBMethod) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{15} +} + +func (x *DBMethod) GetInfluxdb2() *DBMethodInfluxdb2 { + if x != nil { + return x.Influxdb2 + } + return nil +} + +type DBMethodInfluxdb2 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // the config of influx database. + Influxdb2ClientConfig *Influxdb2ClientConfig `protobuf:"bytes,1,opt,name=influxdb2ClientConfig,proto3" json:"influxdb2ClientConfig,omitempty"` + Influxdb2DataConfig *Influxdb2DataConfig `protobuf:"bytes,2,opt,name=influxdb2DataConfig,proto3" json:"influxdb2DataConfig,omitempty"` +} + +func (x *DBMethodInfluxdb2) Reset() { + *x = DBMethodInfluxdb2{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DBMethodInfluxdb2) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DBMethodInfluxdb2) ProtoMessage() {} + +func (x *DBMethodInfluxdb2) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DBMethodInfluxdb2.ProtoReflect.Descriptor instead. +func (*DBMethodInfluxdb2) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{16} +} + +func (x *DBMethodInfluxdb2) GetInfluxdb2ClientConfig() *Influxdb2ClientConfig { + if x != nil { + return x.Influxdb2ClientConfig + } + return nil +} + +func (x *DBMethodInfluxdb2) GetInfluxdb2DataConfig() *Influxdb2DataConfig { + if x != nil { + return x.Influxdb2DataConfig + } + return nil +} + +type Influxdb2DataConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // data config when push data to influx + Measurement string `protobuf:"bytes,1,opt,name=measurement,proto3" json:"measurement,omitempty"` + Tag map[string]string `protobuf:"bytes,2,rep,name=tag,proto3" json:"tag,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + FieldKey string `protobuf:"bytes,3,opt,name=fieldKey,proto3" json:"fieldKey,omitempty"` +} + +func (x *Influxdb2DataConfig) Reset() { + *x = Influxdb2DataConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Influxdb2DataConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Influxdb2DataConfig) ProtoMessage() {} + +func (x *Influxdb2DataConfig) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Influxdb2DataConfig.ProtoReflect.Descriptor instead. +func (*Influxdb2DataConfig) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{17} +} + +func (x *Influxdb2DataConfig) GetMeasurement() string { + if x != nil { + return x.Measurement + } + return "" +} + +func (x *Influxdb2DataConfig) GetTag() map[string]string { + if x != nil { + return x.Tag + } + return nil +} + +func (x *Influxdb2DataConfig) GetFieldKey() string { + if x != nil { + return x.FieldKey + } + return "" +} + +type Influxdb2ClientConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // influx database url + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + // usr org in influx database + Org string `protobuf:"bytes,2,opt,name=org,proto3" json:"org,omitempty"` + // usr bucket in influx database + Bucket string `protobuf:"bytes,3,opt,name=bucket,proto3" json:"bucket,omitempty"` +} + +func (x *Influxdb2ClientConfig) Reset() { + *x = Influxdb2ClientConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Influxdb2ClientConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Influxdb2ClientConfig) ProtoMessage() {} + +func (x *Influxdb2ClientConfig) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Influxdb2ClientConfig.ProtoReflect.Descriptor instead. +func (*Influxdb2ClientConfig) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{18} +} + +func (x *Influxdb2ClientConfig) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *Influxdb2ClientConfig) GetOrg() string { + if x != nil { + return x.Org + } + return "" +} + +func (x *Influxdb2ClientConfig) GetBucket() string { + if x != nil { + return x.Bucket + } + return "" +} + +// MapperInfo is the information of mapper. +type MapperInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // name of the mapper. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // version of the mapper. + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` + // api version of the mapper. + ApiVersion string `protobuf:"bytes,3,opt,name=api_version,json=apiVersion,proto3" json:"api_version,omitempty"` + // the protocol of the mapper. + Protocol string `protobuf:"bytes,4,opt,name=protocol,proto3" json:"protocol,omitempty"` + // the address of the mapper. it is a unix domain socket of grpc. + Address []byte `protobuf:"bytes,5,opt,name=address,proto3" json:"address,omitempty"` + // the state of the mapper. + State string `protobuf:"bytes,6,opt,name=state,proto3" json:"state,omitempty"` +} + +func (x *MapperInfo) Reset() { + *x = MapperInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MapperInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MapperInfo) ProtoMessage() {} + +func (x *MapperInfo) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MapperInfo.ProtoReflect.Descriptor instead. +func (*MapperInfo) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{19} +} + +func (x *MapperInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *MapperInfo) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *MapperInfo) GetApiVersion() string { + if x != nil { + return x.ApiVersion + } + return "" +} + +func (x *MapperInfo) GetProtocol() string { + if x != nil { + return x.Protocol + } + return "" +} + +func (x *MapperInfo) GetAddress() []byte { + if x != nil { + return x.Address + } + return nil +} + +func (x *MapperInfo) GetState() string { + if x != nil { + return x.State + } + return "" +} + +type ReportDeviceStatusRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DeviceName string `protobuf:"bytes,1,opt,name=deviceName,proto3" json:"deviceName,omitempty"` + ReportedDevice *DeviceStatus `protobuf:"bytes,2,opt,name=reportedDevice,proto3" json:"reportedDevice,omitempty"` +} + +func (x *ReportDeviceStatusRequest) Reset() { + *x = ReportDeviceStatusRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReportDeviceStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReportDeviceStatusRequest) ProtoMessage() {} + +func (x *ReportDeviceStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReportDeviceStatusRequest.ProtoReflect.Descriptor instead. +func (*ReportDeviceStatusRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{20} +} + +func (x *ReportDeviceStatusRequest) GetDeviceName() string { + if x != nil { + return x.DeviceName + } + return "" +} + +func (x *ReportDeviceStatusRequest) GetReportedDevice() *DeviceStatus { + if x != nil { + return x.ReportedDevice + } + return nil +} + +// DeviceStatus is the status of the device. +type DeviceStatus struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // the device twins of the device. + Twins []*Twin `protobuf:"bytes,1,rep,name=twins,proto3" json:"twins,omitempty"` +} + +func (x *DeviceStatus) Reset() { + *x = DeviceStatus{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeviceStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeviceStatus) ProtoMessage() {} + +func (x *DeviceStatus) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeviceStatus.ProtoReflect.Descriptor instead. +func (*DeviceStatus) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{21} +} + +func (x *DeviceStatus) GetTwins() []*Twin { + if x != nil { + return x.Twins + } + return nil +} + +// Twin is the digital model of a device. It contains a series of properties. +type Twin struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // the name of the property. + PropertyName string `protobuf:"bytes,1,opt,name=propertyName,proto3" json:"propertyName,omitempty"` + // the observedDesired value of the property configured by mapper. + ObservedDesired *TwinProperty `protobuf:"bytes,2,opt,name=observedDesired,proto3" json:"observedDesired,omitempty"` + // the reported value of the property from the real device. + Reported *TwinProperty `protobuf:"bytes,3,opt,name=reported,proto3" json:"reported,omitempty"` +} + +func (x *Twin) Reset() { + *x = Twin{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Twin) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Twin) ProtoMessage() {} + +func (x *Twin) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Twin.ProtoReflect.Descriptor instead. +func (*Twin) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{22} +} + +func (x *Twin) GetPropertyName() string { + if x != nil { + return x.PropertyName + } + return "" +} + +func (x *Twin) GetObservedDesired() *TwinProperty { + if x != nil { + return x.ObservedDesired + } + return nil +} + +func (x *Twin) GetReported() *TwinProperty { + if x != nil { + return x.Reported + } + return nil +} + +// TwinProperty is the specification of the property. +type TwinProperty struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // the value of the property. + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + // the metadata to describe this property. + Metadata map[string]string `protobuf:"bytes,2,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *TwinProperty) Reset() { + *x = TwinProperty{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TwinProperty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TwinProperty) ProtoMessage() {} + +func (x *TwinProperty) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TwinProperty.ProtoReflect.Descriptor instead. +func (*TwinProperty) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{23} +} + +func (x *TwinProperty) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +func (x *TwinProperty) GetMetadata() map[string]string { + if x != nil { + return x.Metadata + } + return nil +} + +type ReportDeviceStatusResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ReportDeviceStatusResponse) Reset() { + *x = ReportDeviceStatusResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReportDeviceStatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReportDeviceStatusResponse) ProtoMessage() {} + +func (x *ReportDeviceStatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReportDeviceStatusResponse.ProtoReflect.Descriptor instead. +func (*ReportDeviceStatusResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{24} +} + +type RegisterDeviceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Device *Device `protobuf:"bytes,1,opt,name=device,proto3" json:"device,omitempty"` +} + +func (x *RegisterDeviceRequest) Reset() { + *x = RegisterDeviceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterDeviceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterDeviceRequest) ProtoMessage() {} + +func (x *RegisterDeviceRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterDeviceRequest.ProtoReflect.Descriptor instead. +func (*RegisterDeviceRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{25} +} + +func (x *RegisterDeviceRequest) GetDevice() *Device { + if x != nil { + return x.Device + } + return nil +} + +type RegisterDeviceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DeviceName string `protobuf:"bytes,1,opt,name=deviceName,proto3" json:"deviceName,omitempty"` +} + +func (x *RegisterDeviceResponse) Reset() { + *x = RegisterDeviceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterDeviceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterDeviceResponse) ProtoMessage() {} + +func (x *RegisterDeviceResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterDeviceResponse.ProtoReflect.Descriptor instead. +func (*RegisterDeviceResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{26} +} + +func (x *RegisterDeviceResponse) GetDeviceName() string { + if x != nil { + return x.DeviceName + } + return "" +} + +type CreateDeviceModelRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Model *DeviceModel `protobuf:"bytes,1,opt,name=model,proto3" json:"model,omitempty"` +} + +func (x *CreateDeviceModelRequest) Reset() { + *x = CreateDeviceModelRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateDeviceModelRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateDeviceModelRequest) ProtoMessage() {} + +func (x *CreateDeviceModelRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateDeviceModelRequest.ProtoReflect.Descriptor instead. +func (*CreateDeviceModelRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{27} +} + +func (x *CreateDeviceModelRequest) GetModel() *DeviceModel { + if x != nil { + return x.Model + } + return nil +} + +type CreateDeviceModelResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DeviceModelName string `protobuf:"bytes,1,opt,name=deviceModelName,proto3" json:"deviceModelName,omitempty"` +} + +func (x *CreateDeviceModelResponse) Reset() { + *x = CreateDeviceModelResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateDeviceModelResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateDeviceModelResponse) ProtoMessage() {} + +func (x *CreateDeviceModelResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateDeviceModelResponse.ProtoReflect.Descriptor instead. +func (*CreateDeviceModelResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{28} +} + +func (x *CreateDeviceModelResponse) GetDeviceModelName() string { + if x != nil { + return x.DeviceModelName + } + return "" +} + +type RemoveDeviceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DeviceName string `protobuf:"bytes,1,opt,name=deviceName,proto3" json:"deviceName,omitempty"` +} + +func (x *RemoveDeviceRequest) Reset() { + *x = RemoveDeviceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveDeviceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveDeviceRequest) ProtoMessage() {} + +func (x *RemoveDeviceRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveDeviceRequest.ProtoReflect.Descriptor instead. +func (*RemoveDeviceRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{29} +} + +func (x *RemoveDeviceRequest) GetDeviceName() string { + if x != nil { + return x.DeviceName + } + return "" +} + +type RemoveDeviceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RemoveDeviceResponse) Reset() { + *x = RemoveDeviceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveDeviceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveDeviceResponse) ProtoMessage() {} + +func (x *RemoveDeviceResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveDeviceResponse.ProtoReflect.Descriptor instead. +func (*RemoveDeviceResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{30} +} + +type RemoveDeviceModelRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ModelName string `protobuf:"bytes,1,opt,name=modelName,proto3" json:"modelName,omitempty"` +} + +func (x *RemoveDeviceModelRequest) Reset() { + *x = RemoveDeviceModelRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveDeviceModelRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveDeviceModelRequest) ProtoMessage() {} + +func (x *RemoveDeviceModelRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveDeviceModelRequest.ProtoReflect.Descriptor instead. +func (*RemoveDeviceModelRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{31} +} + +func (x *RemoveDeviceModelRequest) GetModelName() string { + if x != nil { + return x.ModelName + } + return "" +} + +type RemoveDeviceModelResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RemoveDeviceModelResponse) Reset() { + *x = RemoveDeviceModelResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveDeviceModelResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveDeviceModelResponse) ProtoMessage() {} + +func (x *RemoveDeviceModelResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveDeviceModelResponse.ProtoReflect.Descriptor instead. +func (*RemoveDeviceModelResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{32} +} + +type UpdateDeviceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Device *Device `protobuf:"bytes,1,opt,name=device,proto3" json:"device,omitempty"` +} + +func (x *UpdateDeviceRequest) Reset() { + *x = UpdateDeviceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateDeviceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateDeviceRequest) ProtoMessage() {} + +func (x *UpdateDeviceRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateDeviceRequest.ProtoReflect.Descriptor instead. +func (*UpdateDeviceRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{33} +} + +func (x *UpdateDeviceRequest) GetDevice() *Device { + if x != nil { + return x.Device + } + return nil +} + +type UpdateDeviceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateDeviceResponse) Reset() { + *x = UpdateDeviceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateDeviceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateDeviceResponse) ProtoMessage() {} + +func (x *UpdateDeviceResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateDeviceResponse.ProtoReflect.Descriptor instead. +func (*UpdateDeviceResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{34} +} + +type UpdateDeviceModelRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Model *DeviceModel `protobuf:"bytes,1,opt,name=model,proto3" json:"model,omitempty"` +} + +func (x *UpdateDeviceModelRequest) Reset() { + *x = UpdateDeviceModelRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateDeviceModelRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateDeviceModelRequest) ProtoMessage() {} + +func (x *UpdateDeviceModelRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateDeviceModelRequest.ProtoReflect.Descriptor instead. +func (*UpdateDeviceModelRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{35} +} + +func (x *UpdateDeviceModelRequest) GetModel() *DeviceModel { + if x != nil { + return x.Model + } + return nil +} + +type UpdateDeviceModelResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateDeviceModelResponse) Reset() { + *x = UpdateDeviceModelResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateDeviceModelResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateDeviceModelResponse) ProtoMessage() {} + +func (x *UpdateDeviceModelResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateDeviceModelResponse.ProtoReflect.Descriptor instead. +func (*UpdateDeviceModelResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{36} +} + +type GetDeviceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DeviceName string `protobuf:"bytes,1,opt,name=deviceName,proto3" json:"deviceName,omitempty"` +} + +func (x *GetDeviceRequest) Reset() { + *x = GetDeviceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetDeviceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetDeviceRequest) ProtoMessage() {} + +func (x *GetDeviceRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[37] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetDeviceRequest.ProtoReflect.Descriptor instead. +func (*GetDeviceRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{37} +} + +func (x *GetDeviceRequest) GetDeviceName() string { + if x != nil { + return x.DeviceName + } + return "" +} + +type GetDeviceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Device *Device `protobuf:"bytes,1,opt,name=device,proto3" json:"device,omitempty"` +} + +func (x *GetDeviceResponse) Reset() { + *x = GetDeviceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetDeviceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetDeviceResponse) ProtoMessage() {} + +func (x *GetDeviceResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[38] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetDeviceResponse.ProtoReflect.Descriptor instead. +func (*GetDeviceResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{38} +} + +func (x *GetDeviceResponse) GetDevice() *Device { + if x != nil { + return x.Device + } + return nil +} + +var File_api_proto protoreflect.FileDescriptor + +var file_api_proto_rawDesc = []byte{ + 0x0a, 0x09, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x60, 0x0a, 0x15, 0x4d, 0x61, 0x70, 0x70, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x69, 0x74, 0x68, + 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x77, 0x69, 0x74, 0x68, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x2b, 0x0a, 0x06, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, + 0x61, 0x70, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x6d, 0x61, 0x70, 0x70, 0x65, + 0x72, 0x22, 0x7d, 0x0a, 0x16, 0x4d, 0x61, 0x70, 0x70, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x09, 0x6d, + 0x6f, 0x64, 0x65, 0x6c, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, + 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x4c, 0x69, 0x73, 0x74, 0x12, + 0x2f, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, + 0x22, 0x4f, 0x0a, 0x0b, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, + 0x63, 0x22, 0x7d, 0x0a, 0x0f, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, + 0x53, 0x70, 0x65, 0x63, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, + 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x08, + 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, + 0x22, 0xc1, 0x01, 0x0a, 0x0d, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x0a, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, + 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, + 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x75, 0x6e, 0x69, 0x74, 0x22, 0xaa, 0x01, 0x0a, 0x0d, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, + 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, + 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, + 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x74, 0x0a, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x27, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x70, + 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x2d, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xae, 0x01, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x32, 0x0a, 0x14, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, + 0x6c, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x08, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, + 0x37, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x0a, 0x70, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0xaa, 0x02, 0x0a, 0x0e, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x2f, 0x0a, 0x07, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, 0x77, 0x69, 0x6e, 0x50, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x07, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, + 0x12, 0x32, 0x0a, 0x08, 0x76, 0x69, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x56, 0x69, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x76, 0x69, 0x73, 0x69, + 0x74, 0x6f, 0x72, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x79, + 0x63, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x72, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x54, 0x6f, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0d, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x6f, 0x43, 0x6c, 0x6f, 0x75, 0x64, + 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x75, 0x73, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, + 0x75, 0x73, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0a, 0x70, 0x75, 0x73, 0x68, 0x4d, + 0x65, 0x74, 0x68, 0x6f, 0x64, 0x22, 0x6e, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0a, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, + 0x69, 0x7a, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x44, 0x61, 0x74, 0x61, 0x22, 0x6d, 0x0a, 0x0d, 0x56, 0x69, 0x73, 0x69, 0x74, 0x6f, 0x72, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0a, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x69, + 0x7a, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x44, 0x61, 0x74, 0x61, 0x22, 0x98, 0x01, 0x0a, 0x0f, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x69, + 0x7a, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x1a, 0x4d, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0x95, 0x01, 0x0a, 0x0a, 0x50, 0x75, 0x73, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x2b, + 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x48, 0x54, 0x54, 0x50, 0x52, 0x04, 0x68, 0x74, 0x74, 0x70, 0x12, 0x2b, 0x0a, 0x04, 0x6d, + 0x71, 0x74, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4d, 0x51, + 0x54, 0x54, 0x52, 0x04, 0x6d, 0x71, 0x74, 0x74, 0x12, 0x2d, 0x0a, 0x08, 0x64, 0x62, 0x4d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x42, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x08, 0x64, + 0x62, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x22, 0x7c, 0x0a, 0x0e, 0x50, 0x75, 0x73, 0x68, 0x4d, + 0x65, 0x74, 0x68, 0x6f, 0x64, 0x48, 0x54, 0x54, 0x50, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, + 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, + 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x70, 0x61, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x74, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, + 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x6e, 0x0a, 0x0e, 0x50, 0x75, 0x73, 0x68, 0x4d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x4d, 0x51, 0x54, 0x54, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x71, 0x6f, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x71, 0x6f, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x64, 0x22, 0x44, 0x0a, 0x08, 0x44, 0x42, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x12, 0x38, 0x0a, 0x09, 0x69, 0x6e, 0x66, 0x6c, 0x75, 0x78, 0x64, 0x62, 0x32, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, + 0x42, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x49, 0x6e, 0x66, 0x6c, 0x75, 0x78, 0x64, 0x62, 0x32, + 0x52, 0x09, 0x69, 0x6e, 0x66, 0x6c, 0x75, 0x78, 0x64, 0x62, 0x32, 0x22, 0xb9, 0x01, 0x0a, 0x11, + 0x44, 0x42, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x49, 0x6e, 0x66, 0x6c, 0x75, 0x78, 0x64, 0x62, + 0x32, 0x12, 0x54, 0x0a, 0x15, 0x69, 0x6e, 0x66, 0x6c, 0x75, 0x78, 0x64, 0x62, 0x32, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6c, 0x75, + 0x78, 0x64, 0x62, 0x32, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x15, 0x69, 0x6e, 0x66, 0x6c, 0x75, 0x78, 0x64, 0x62, 0x32, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4e, 0x0a, 0x13, 0x69, 0x6e, 0x66, 0x6c, 0x75, + 0x78, 0x64, 0x62, 0x32, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x49, + 0x6e, 0x66, 0x6c, 0x75, 0x78, 0x64, 0x62, 0x32, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x13, 0x69, 0x6e, 0x66, 0x6c, 0x75, 0x78, 0x64, 0x62, 0x32, 0x44, 0x61, 0x74, + 0x61, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xc4, 0x01, 0x0a, 0x13, 0x49, 0x6e, 0x66, 0x6c, + 0x75, 0x78, 0x64, 0x62, 0x32, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, + 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x37, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x49, 0x6e, 0x66, 0x6c, 0x75, 0x78, 0x64, + 0x62, 0x32, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x54, 0x61, 0x67, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x4b, 0x65, 0x79, 0x1a, 0x36, 0x0a, 0x08, 0x54, 0x61, 0x67, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x53, + 0x0a, 0x15, 0x49, 0x6e, 0x66, 0x6c, 0x75, 0x78, 0x64, 0x62, 0x32, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x10, 0x0a, 0x03, 0x6f, 0x72, 0x67, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6f, 0x72, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x62, + 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x22, 0xa7, 0x01, 0x0a, 0x0a, 0x4d, 0x61, 0x70, 0x70, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x18, 0x0a, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x7a, 0x0a, + 0x19, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x0e, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0e, 0x72, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0x33, 0x0a, 0x0c, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x23, 0x0a, 0x05, 0x74, 0x77, 0x69, + 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x54, 0x77, 0x69, 0x6e, 0x52, 0x05, 0x74, 0x77, 0x69, 0x6e, 0x73, 0x22, 0x9e, + 0x01, 0x0a, 0x04, 0x54, 0x77, 0x69, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x0f, 0x6f, + 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, + 0x77, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x0f, 0x6f, 0x62, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x64, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x08, + 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, 0x77, 0x69, 0x6e, 0x50, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x08, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x22, + 0xa2, 0x01, 0x0a, 0x0c, 0x54, 0x77, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x54, 0x77, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x2e, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0x1c, 0x0a, 0x1a, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x40, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x06, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x06, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x22, 0x38, 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x46, + 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, + 0x64, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, + 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x22, 0x45, 0x0a, 0x19, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, + 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x35, 0x0a, + 0x13, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, 0x0a, 0x18, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, + 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, + 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x3e, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x06, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x06, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x46, 0x0a, 0x18, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x05, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x22, 0x1b, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x32, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3c, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x32, 0xcc, 0x01, 0x0a, 0x14, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x53, 0x0a, 0x0e, 0x4d, + 0x61, 0x70, 0x70, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x61, 0x70, 0x70, 0x65, 0x72, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x61, 0x70, 0x70, 0x65, 0x72, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x5f, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x22, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x32, 0xe8, 0x04, 0x0a, 0x13, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x70, 0x70, + 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x53, 0x0a, 0x0e, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1e, 0x2e, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4d, + 0x0a, 0x0c, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1c, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, + 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1c, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5c, 0x0a, 0x11, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, + 0x6c, 0x12, 0x21, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5c, 0x0a, 0x11, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, + 0x21, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5c, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x21, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x22, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x19, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0c, 0x5a, 0x0a, + 0x2e, 0x2f, 0x3b, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_api_proto_rawDescOnce sync.Once + file_api_proto_rawDescData = file_api_proto_rawDesc +) + +func file_api_proto_rawDescGZIP() []byte { + file_api_proto_rawDescOnce.Do(func() { + file_api_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_proto_rawDescData) + }) + return file_api_proto_rawDescData +} + +var file_api_proto_msgTypes = make([]protoimpl.MessageInfo, 42) +var file_api_proto_goTypes = []interface{}{ + (*MapperRegisterRequest)(nil), // 0: v1beta1.MapperRegisterRequest + (*MapperRegisterResponse)(nil), // 1: v1beta1.MapperRegisterResponse + (*DeviceModel)(nil), // 2: v1beta1.DeviceModel + (*DeviceModelSpec)(nil), // 3: v1beta1.DeviceModelSpec + (*ModelProperty)(nil), // 4: v1beta1.ModelProperty + (*DeviceCommand)(nil), // 5: v1beta1.DeviceCommand + (*Device)(nil), // 6: v1beta1.Device + (*DeviceSpec)(nil), // 7: v1beta1.DeviceSpec + (*DeviceProperty)(nil), // 8: v1beta1.DeviceProperty + (*ProtocolConfig)(nil), // 9: v1beta1.ProtocolConfig + (*VisitorConfig)(nil), // 10: v1beta1.VisitorConfig + (*CustomizedValue)(nil), // 11: v1beta1.CustomizedValue + (*PushMethod)(nil), // 12: v1beta1.PushMethod + (*PushMethodHTTP)(nil), // 13: v1beta1.PushMethodHTTP + (*PushMethodMQTT)(nil), // 14: v1beta1.PushMethodMQTT + (*DBMethod)(nil), // 15: v1beta1.DBMethod + (*DBMethodInfluxdb2)(nil), // 16: v1beta1.DBMethodInfluxdb2 + (*Influxdb2DataConfig)(nil), // 17: v1beta1.Influxdb2DataConfig + (*Influxdb2ClientConfig)(nil), // 18: v1beta1.Influxdb2ClientConfig + (*MapperInfo)(nil), // 19: v1beta1.MapperInfo + (*ReportDeviceStatusRequest)(nil), // 20: v1beta1.ReportDeviceStatusRequest + (*DeviceStatus)(nil), // 21: v1beta1.DeviceStatus + (*Twin)(nil), // 22: v1beta1.Twin + (*TwinProperty)(nil), // 23: v1beta1.TwinProperty + (*ReportDeviceStatusResponse)(nil), // 24: v1beta1.ReportDeviceStatusResponse + (*RegisterDeviceRequest)(nil), // 25: v1beta1.RegisterDeviceRequest + (*RegisterDeviceResponse)(nil), // 26: v1beta1.RegisterDeviceResponse + (*CreateDeviceModelRequest)(nil), // 27: v1beta1.CreateDeviceModelRequest + (*CreateDeviceModelResponse)(nil), // 28: v1beta1.CreateDeviceModelResponse + (*RemoveDeviceRequest)(nil), // 29: v1beta1.RemoveDeviceRequest + (*RemoveDeviceResponse)(nil), // 30: v1beta1.RemoveDeviceResponse + (*RemoveDeviceModelRequest)(nil), // 31: v1beta1.RemoveDeviceModelRequest + (*RemoveDeviceModelResponse)(nil), // 32: v1beta1.RemoveDeviceModelResponse + (*UpdateDeviceRequest)(nil), // 33: v1beta1.UpdateDeviceRequest + (*UpdateDeviceResponse)(nil), // 34: v1beta1.UpdateDeviceResponse + (*UpdateDeviceModelRequest)(nil), // 35: v1beta1.UpdateDeviceModelRequest + (*UpdateDeviceModelResponse)(nil), // 36: v1beta1.UpdateDeviceModelResponse + (*GetDeviceRequest)(nil), // 37: v1beta1.GetDeviceRequest + (*GetDeviceResponse)(nil), // 38: v1beta1.GetDeviceResponse + nil, // 39: v1beta1.CustomizedValue.DataEntry + nil, // 40: v1beta1.Influxdb2DataConfig.TagEntry + nil, // 41: v1beta1.TwinProperty.MetadataEntry + (*anypb.Any)(nil), // 42: google.protobuf.Any +} +var file_api_proto_depIdxs = []int32{ + 19, // 0: v1beta1.MapperRegisterRequest.mapper:type_name -> v1beta1.MapperInfo + 2, // 1: v1beta1.MapperRegisterResponse.modelList:type_name -> v1beta1.DeviceModel + 6, // 2: v1beta1.MapperRegisterResponse.deviceList:type_name -> v1beta1.Device + 3, // 3: v1beta1.DeviceModel.spec:type_name -> v1beta1.DeviceModelSpec + 4, // 4: v1beta1.DeviceModelSpec.properties:type_name -> v1beta1.ModelProperty + 5, // 5: v1beta1.DeviceModelSpec.commands:type_name -> v1beta1.DeviceCommand + 7, // 6: v1beta1.Device.spec:type_name -> v1beta1.DeviceSpec + 21, // 7: v1beta1.Device.status:type_name -> v1beta1.DeviceStatus + 9, // 8: v1beta1.DeviceSpec.protocol:type_name -> v1beta1.ProtocolConfig + 8, // 9: v1beta1.DeviceSpec.properties:type_name -> v1beta1.DeviceProperty + 23, // 10: v1beta1.DeviceProperty.desired:type_name -> v1beta1.TwinProperty + 10, // 11: v1beta1.DeviceProperty.visitors:type_name -> v1beta1.VisitorConfig + 12, // 12: v1beta1.DeviceProperty.pushMethod:type_name -> v1beta1.PushMethod + 11, // 13: v1beta1.ProtocolConfig.configData:type_name -> v1beta1.CustomizedValue + 11, // 14: v1beta1.VisitorConfig.configData:type_name -> v1beta1.CustomizedValue + 39, // 15: v1beta1.CustomizedValue.data:type_name -> v1beta1.CustomizedValue.DataEntry + 13, // 16: v1beta1.PushMethod.http:type_name -> v1beta1.PushMethodHTTP + 14, // 17: v1beta1.PushMethod.mqtt:type_name -> v1beta1.PushMethodMQTT + 15, // 18: v1beta1.PushMethod.dbMethod:type_name -> v1beta1.DBMethod + 16, // 19: v1beta1.DBMethod.influxdb2:type_name -> v1beta1.DBMethodInfluxdb2 + 18, // 20: v1beta1.DBMethodInfluxdb2.influxdb2ClientConfig:type_name -> v1beta1.Influxdb2ClientConfig + 17, // 21: v1beta1.DBMethodInfluxdb2.influxdb2DataConfig:type_name -> v1beta1.Influxdb2DataConfig + 40, // 22: v1beta1.Influxdb2DataConfig.tag:type_name -> v1beta1.Influxdb2DataConfig.TagEntry + 21, // 23: v1beta1.ReportDeviceStatusRequest.reportedDevice:type_name -> v1beta1.DeviceStatus + 22, // 24: v1beta1.DeviceStatus.twins:type_name -> v1beta1.Twin + 23, // 25: v1beta1.Twin.observedDesired:type_name -> v1beta1.TwinProperty + 23, // 26: v1beta1.Twin.reported:type_name -> v1beta1.TwinProperty + 41, // 27: v1beta1.TwinProperty.metadata:type_name -> v1beta1.TwinProperty.MetadataEntry + 6, // 28: v1beta1.RegisterDeviceRequest.device:type_name -> v1beta1.Device + 2, // 29: v1beta1.CreateDeviceModelRequest.model:type_name -> v1beta1.DeviceModel + 6, // 30: v1beta1.UpdateDeviceRequest.device:type_name -> v1beta1.Device + 2, // 31: v1beta1.UpdateDeviceModelRequest.model:type_name -> v1beta1.DeviceModel + 6, // 32: v1beta1.GetDeviceResponse.device:type_name -> v1beta1.Device + 42, // 33: v1beta1.CustomizedValue.DataEntry.value:type_name -> google.protobuf.Any + 0, // 34: v1beta1.DeviceManagerService.MapperRegister:input_type -> v1beta1.MapperRegisterRequest + 20, // 35: v1beta1.DeviceManagerService.ReportDeviceStatus:input_type -> v1beta1.ReportDeviceStatusRequest + 25, // 36: v1beta1.DeviceMapperService.RegisterDevice:input_type -> v1beta1.RegisterDeviceRequest + 29, // 37: v1beta1.DeviceMapperService.RemoveDevice:input_type -> v1beta1.RemoveDeviceRequest + 33, // 38: v1beta1.DeviceMapperService.UpdateDevice:input_type -> v1beta1.UpdateDeviceRequest + 27, // 39: v1beta1.DeviceMapperService.CreateDeviceModel:input_type -> v1beta1.CreateDeviceModelRequest + 31, // 40: v1beta1.DeviceMapperService.RemoveDeviceModel:input_type -> v1beta1.RemoveDeviceModelRequest + 35, // 41: v1beta1.DeviceMapperService.UpdateDeviceModel:input_type -> v1beta1.UpdateDeviceModelRequest + 37, // 42: v1beta1.DeviceMapperService.GetDevice:input_type -> v1beta1.GetDeviceRequest + 1, // 43: v1beta1.DeviceManagerService.MapperRegister:output_type -> v1beta1.MapperRegisterResponse + 24, // 44: v1beta1.DeviceManagerService.ReportDeviceStatus:output_type -> v1beta1.ReportDeviceStatusResponse + 26, // 45: v1beta1.DeviceMapperService.RegisterDevice:output_type -> v1beta1.RegisterDeviceResponse + 30, // 46: v1beta1.DeviceMapperService.RemoveDevice:output_type -> v1beta1.RemoveDeviceResponse + 34, // 47: v1beta1.DeviceMapperService.UpdateDevice:output_type -> v1beta1.UpdateDeviceResponse + 28, // 48: v1beta1.DeviceMapperService.CreateDeviceModel:output_type -> v1beta1.CreateDeviceModelResponse + 32, // 49: v1beta1.DeviceMapperService.RemoveDeviceModel:output_type -> v1beta1.RemoveDeviceModelResponse + 36, // 50: v1beta1.DeviceMapperService.UpdateDeviceModel:output_type -> v1beta1.UpdateDeviceModelResponse + 38, // 51: v1beta1.DeviceMapperService.GetDevice:output_type -> v1beta1.GetDeviceResponse + 43, // [43:52] is the sub-list for method output_type + 34, // [34:43] is the sub-list for method input_type + 34, // [34:34] is the sub-list for extension type_name + 34, // [34:34] is the sub-list for extension extendee + 0, // [0:34] is the sub-list for field type_name +} + +func init() { file_api_proto_init() } +func file_api_proto_init() { + if File_api_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MapperRegisterRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MapperRegisterResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeviceModel); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeviceModelSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ModelProperty); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeviceCommand); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Device); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeviceSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeviceProperty); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProtocolConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VisitorConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CustomizedValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushMethod); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushMethodHTTP); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushMethodMQTT); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DBMethod); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DBMethodInfluxdb2); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Influxdb2DataConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Influxdb2ClientConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MapperInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReportDeviceStatusRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeviceStatus); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Twin); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TwinProperty); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReportDeviceStatusResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterDeviceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterDeviceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateDeviceModelRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateDeviceModelResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoveDeviceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoveDeviceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoveDeviceModelRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoveDeviceModelResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateDeviceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateDeviceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateDeviceModelRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateDeviceModelResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetDeviceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetDeviceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_api_proto_rawDesc, + NumEnums: 0, + NumMessages: 42, + NumExtensions: 0, + NumServices: 2, + }, + GoTypes: file_api_proto_goTypes, + DependencyIndexes: file_api_proto_depIdxs, + MessageInfos: file_api_proto_msgTypes, + }.Build() + File_api_proto = out.File + file_api_proto_rawDesc = nil + file_api_proto_goTypes = nil + file_api_proto_depIdxs = nil +} + +func NewMapperClient(cc grpc.ClientConnInterface) DeviceMapperServiceClient { + return &deviceMapperServiceClient{cc} +} + +func NewDeviceManageClient(cc grpc.ClientConnInterface) DeviceManagerServiceClient { + return &deviceManagerServiceClient{cc} +} diff --git a/mappers/usbcamera-dmi/pkg/dmi-api/api.proto b/mappers/usbcamera-dmi/pkg/dmi-api/api.proto new file mode 100755 index 00000000..a6f94859 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/dmi-api/api.proto @@ -0,0 +1,365 @@ +/* +Copyright 2023 The KubeEdge Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// To regenerate api.pb.go run hack/generate-dmi.sh +syntax = "proto3"; + +//option go_package = "path;name"; +option go_package = "./;v1beta1"; +package v1beta1; + +import "google/protobuf/any.proto"; + +// DeviceManagerService defines the public APIS for remote device management. +// The server is implemented by the module of device manager in edgecore +// and the client is implemented by the device mapper for upstreaming. +// The mapper should register itself to the device manager when it is online +// to get the list of devices. And then the mapper can report the device status to the device manager. +service DeviceManagerService { + // MapperRegister registers the information of the mapper to device manager + // when the mapper is online. Device manager returns the list of devices and device models which + // this mapper should manage. + rpc MapperRegister(MapperRegisterRequest) returns (MapperRegisterResponse) {} + // ReportDeviceStatus reports the status of devices to device manager. + // When the mapper collects some properties of a device, it can make them a map of device twins + // and report it to the device manager through the interface of ReportDeviceStatus. + rpc ReportDeviceStatus(ReportDeviceStatusRequest) returns (ReportDeviceStatusResponse) {} +} + +// DeviceMapperService defines the public APIS for remote device management. +// The server is implemented by the device mapper +// and the client is implemented by the module of device manager in edgecore for downstreaming. +// The device manager can manage the device life cycle through these interfaces provided by DeviceMapperService. +// When device manager gets a message of device management from cloudcore, it should call the corresponding grpc interface +// to make the mapper maintain the list of device information. +service DeviceMapperService { + // RegisterDevice registers a device to the device mapper. + // Device manager registers a device instance with the information of device + // to the mapper through the interface of RegisterDevice. + // When the mapper gets the request of register with device information, + // it should add the device to the device list and connect to the real physical device via the specific protocol. + rpc RegisterDevice(RegisterDeviceRequest) returns (RegisterDeviceResponse) {} + // RemoveDevice unregisters a device to the device mapper. + // Device manager unregisters a device instance with the name of device + // to the mapper through the interface of RemoveDevice. + // When the mapper gets the request of unregister with device name, + // it should remove the device from the device list and disconnect to the real physical device. + rpc RemoveDevice(RemoveDeviceRequest) returns (RemoveDeviceResponse) {} + // UpdateDevice updates a device to the device mapper + // Device manager updates the information of a device used by the mapper + // through the interface of UpdateDevice. + // The information of a device includes the meta data and the status data of a device. + // When the mapper gets the request of updating with the information of a device, + // it should update the device of the device list and connect to the real physical device via the updated information. + rpc UpdateDevice(UpdateDeviceRequest) returns (UpdateDeviceResponse) {} + // CreateDeviceModel creates a device model to the device mapper. + // Device manager sends the information of device model to the mapper + // through the interface of CreateDeviceModel. + // When the mapper gets the request of creating with the information of device model, + // it should create a new device model to the list of device models. + rpc CreateDeviceModel(CreateDeviceModelRequest) returns (CreateDeviceModelResponse) {} + // RemoveDeviceModel remove a device model to the device mapper. + // Device manager sends the name of device model to the mapper + // through the interface of RemoveDeviceModel. + // When the mapper gets the request of removing with the name of device model, + // it should remove the device model to the list of device models. + rpc RemoveDeviceModel(RemoveDeviceModelRequest) returns (RemoveDeviceModelResponse) {} + // UpdateDeviceModel update a device model to the device mapper. + // Device manager sends the information of device model to the mapper + // through the interface of UpdateDeviceModel. + // When the mapper gets the request of updating with the information of device model, + // it should update the device model to the list of device models. + rpc UpdateDeviceModel(UpdateDeviceModelRequest) returns (UpdateDeviceModelResponse) {} + // GetDevice get the information of a device from the device mapper. + // Device sends the request of querying device information with the device name to the mapper + // through the interface of GetDevice. + // When the mapper gets the request of querying with the device name, + // it should return the device information. + rpc GetDevice(GetDeviceRequest) returns (GetDeviceResponse) {} +} + +message MapperRegisterRequest { + // The flag to show how device manager returns. + // True means device manager should return the device list in the response. + // False means device manager should just return nothing. + bool withData = 1; + // Mapper information to be registered to the device manager. + MapperInfo mapper = 2; +} + +message MapperRegisterResponse { + // List of device models which the mapper maintains. + repeated DeviceModel modelList = 1; + // List of devices which the mapper maintains. + repeated Device deviceList = 2; +} + +// DeviceModel specifies the information of a device model. +message DeviceModel { + // Name of a device model. + string name = 1; + // Specification of a device model. + DeviceModelSpec spec = 2; +} + +// DeviceModelSpec is the specification of a device model. +message DeviceModelSpec { + // The properties provided by the device of this device model. + repeated ModelProperty properties = 1; + // The commands executed by the device of this device model. + repeated DeviceCommand commands = 2; +} + +// ModelProperty is the property of a device. +message ModelProperty { + // The name of this property. + string name = 1; + // The description of this property. + string description = 2; + // The specific type of this property. + string type = 3; + // The access mode of this property, ReadOnly or ReadWrite. + string accessMode = 4; + // The minimum value of this property. + string minimum = 5; + // The maximum value of this property. + string maximum = 6; + // The unit of this property. + string unit = 7; +} + +// DeviceCommond is the description of a command which the device supports. +message DeviceCommand { + // Name of the command. + string name = 1; + // Url of the command to access. + string url = 2; + // Method of the command. + string method = 3; + // Status code list which the command can return. + repeated string status_code = 4; + // Parameter list which the command carries. + repeated string parameters = 5; + // Response examples of the command. + bytes response = 6; +} + +// Device is the description of a device instance. +message Device { + // Name of the device. + string name = 1; + // Specification of the device. + DeviceSpec spec = 2; + // Status of the device. + DeviceStatus status = 3; +} + +// DeviceSpec is the specification of the device. +message DeviceSpec { + // The device model which the device references. + string deviceModelReference = 1; + // The specific config of the protocol to access to the device. + ProtocolConfig protocol = 2; + // List of properties which describe the device properties. + repeated DeviceProperty properties = 3; +} + +// DeviceProperty describes the specifics all the properties of the device. +message DeviceProperty { + // The device property name to be accessed. It must be unique. + string name = 1; + // the desired value of the property configured by device manager. + TwinProperty desired = 2; + // Visitors are intended to be consumed by device mappers which connect to devices + // and collect data / perform actions on the device. + VisitorConfig visitors = 3; + // Define how frequent mapper will report the value. + int64 reportCycle = 4; + // Define how frequent mapper will collect from device. + int64 collectCycle = 5; + // whether be reported to the cloud + bool reportToCloud = 6; + // PushMethod represents the protocol used to push data, + PushMethod pushMethod = 7; +} + +// ProtocolConfig is the specific config of the protocol to access to the device. +message ProtocolConfig { + // the name of the customized protocol. + string protocolName = 1; + // the config data of the customized protocol. + CustomizedValue configData = 2; +} + +// the visitor to collect the properties of the device of customized protocol. +message VisitorConfig { + // the name of the customized protocol. + string protocolName = 1; + // the config data of the customized protocol. + CustomizedValue configData = 2; +} + +// CustomizedValue is the customized value for developers. +message CustomizedValue { + // data is the customized value and it can be any form. + map data = 1; +} + +message PushMethod { + PushMethodHTTP http = 1; + PushMethodMQTT mqtt = 2; + DBMethod dbMethod = 3; +} + +message PushMethodHTTP { + string hostname = 1; + int64 port = 2; + string requestpath = 3; + int64 timeout = 4; +} + +message PushMethodMQTT { + // broker address, like mqtt://127.0.0.1:1883 + string address = 1; + // publish topic for mqtt + string topic = 2; + // qos of mqtt publish param + int32 qos = 3; + // Is the message retained + bool retained = 4; +} + +message DBMethod{ + // the config of database . + DBMethodInfluxdb2 influxdb2 = 1; +} + +message DBMethodInfluxdb2{ + // the config of influx database. + Influxdb2ClientConfig influxdb2ClientConfig = 1; + Influxdb2DataConfig influxdb2DataConfig = 2; +} + +message Influxdb2DataConfig{ + // data config when push data to influx + string measurement = 1; + map tag = 2; + string fieldKey = 3; +} + +message Influxdb2ClientConfig{ + // influx database url + string url = 1; + // usr org in influx database + string org = 2; + // usr bucket in influx database + string bucket = 3; +} + +// MapperInfo is the information of mapper. +message MapperInfo { + // name of the mapper. + string name = 1; + // version of the mapper. + string version = 2; + // api version of the mapper. + string api_version = 3; + // the protocol of the mapper. + string protocol = 4; + // the address of the mapper. it is a unix domain socket of grpc. + bytes address = 5; + // the state of the mapper. + string state = 6; +} + +message ReportDeviceStatusRequest { + string deviceName = 1; + DeviceStatus reportedDevice = 2; +} + +// DeviceStatus is the status of the device. +message DeviceStatus { + // the device twins of the device. + repeated Twin twins = 1; +} + +// Twin is the digital model of a device. It contains a series of properties. +message Twin { + // the name of the property. + string propertyName = 1; + // the observedDesired value of the property configured by mapper. + TwinProperty observedDesired = 2; + // the reported value of the property from the real device. + TwinProperty reported = 3; +} + +// TwinProperty is the specification of the property. +message TwinProperty { + // the value of the property. + string value = 1; + // the metadata to describe this property. + map metadata = 2; +} + +message ReportDeviceStatusResponse {} + +message RegisterDeviceRequest { + Device device = 1; +} + +message RegisterDeviceResponse { + string deviceName = 1; +} + +message CreateDeviceModelRequest { + DeviceModel model = 1; +} + +message CreateDeviceModelResponse { + string deviceModelName = 1; +} + +message RemoveDeviceRequest { + string deviceName = 1; +} + +message RemoveDeviceResponse {} + +message RemoveDeviceModelRequest { + string modelName = 1; +} + +message RemoveDeviceModelResponse {} + +message UpdateDeviceRequest { + Device device = 1; +} + +message UpdateDeviceResponse {} + +message UpdateDeviceModelRequest { + DeviceModel model = 1; +} + +message UpdateDeviceModelResponse {} + +message GetDeviceRequest { + string deviceName = 1; +} + +message GetDeviceResponse { + Device device = 1; +} diff --git a/mappers/usbcamera-dmi/pkg/dmi-api/api_grpc.pb.go b/mappers/usbcamera-dmi/pkg/dmi-api/api_grpc.pb.go new file mode 100755 index 00000000..092fdb34 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/dmi-api/api_grpc.pb.go @@ -0,0 +1,559 @@ +// +//Copyright 2023 The KubeEdge Authors. +// +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +// +//http://www.apache.org/licenses/LICENSE-2.0 +// +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. + +// To regenerate api.pb.go run hack/generate-dmi.sh + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v3.19.4 +// source: api.proto + +package v1beta1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + DeviceManagerService_MapperRegister_FullMethodName = "/v1beta1.DeviceManagerService/MapperRegister" + DeviceManagerService_ReportDeviceStatus_FullMethodName = "/v1beta1.DeviceManagerService/ReportDeviceStatus" +) + +// DeviceManagerServiceClient is the client API for DeviceManagerService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type DeviceManagerServiceClient interface { + // MapperRegister registers the information of the mapper to device manager + // when the mapper is online. Device manager returns the list of devices and device models which + // this mapper should manage. + MapperRegister(ctx context.Context, in *MapperRegisterRequest, opts ...grpc.CallOption) (*MapperRegisterResponse, error) + // ReportDeviceStatus reports the status of devices to device manager. + // When the mapper collects some properties of a device, it can make them a map of device twins + // and report it to the device manager through the interface of ReportDeviceStatus. + ReportDeviceStatus(ctx context.Context, in *ReportDeviceStatusRequest, opts ...grpc.CallOption) (*ReportDeviceStatusResponse, error) +} + +type deviceManagerServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewDeviceManagerServiceClient(cc grpc.ClientConnInterface) DeviceManagerServiceClient { + return &deviceManagerServiceClient{cc} +} + +func (c *deviceManagerServiceClient) MapperRegister(ctx context.Context, in *MapperRegisterRequest, opts ...grpc.CallOption) (*MapperRegisterResponse, error) { + out := new(MapperRegisterResponse) + err := c.cc.Invoke(ctx, DeviceManagerService_MapperRegister_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *deviceManagerServiceClient) ReportDeviceStatus(ctx context.Context, in *ReportDeviceStatusRequest, opts ...grpc.CallOption) (*ReportDeviceStatusResponse, error) { + out := new(ReportDeviceStatusResponse) + err := c.cc.Invoke(ctx, DeviceManagerService_ReportDeviceStatus_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DeviceManagerServiceServer is the server API for DeviceManagerService service. +// All implementations must embed UnimplementedDeviceManagerServiceServer +// for forward compatibility +type DeviceManagerServiceServer interface { + // MapperRegister registers the information of the mapper to device manager + // when the mapper is online. Device manager returns the list of devices and device models which + // this mapper should manage. + MapperRegister(context.Context, *MapperRegisterRequest) (*MapperRegisterResponse, error) + // ReportDeviceStatus reports the status of devices to device manager. + // When the mapper collects some properties of a device, it can make them a map of device twins + // and report it to the device manager through the interface of ReportDeviceStatus. + ReportDeviceStatus(context.Context, *ReportDeviceStatusRequest) (*ReportDeviceStatusResponse, error) + mustEmbedUnimplementedDeviceManagerServiceServer() +} + +// UnimplementedDeviceManagerServiceServer must be embedded to have forward compatible implementations. +type UnimplementedDeviceManagerServiceServer struct { +} + +func (UnimplementedDeviceManagerServiceServer) MapperRegister(context.Context, *MapperRegisterRequest) (*MapperRegisterResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method MapperRegister not implemented") +} +func (UnimplementedDeviceManagerServiceServer) ReportDeviceStatus(context.Context, *ReportDeviceStatusRequest) (*ReportDeviceStatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReportDeviceStatus not implemented") +} +func (UnimplementedDeviceManagerServiceServer) mustEmbedUnimplementedDeviceManagerServiceServer() {} + +// UnsafeDeviceManagerServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to DeviceManagerServiceServer will +// result in compilation errors. +type UnsafeDeviceManagerServiceServer interface { + mustEmbedUnimplementedDeviceManagerServiceServer() +} + +func RegisterDeviceManagerServiceServer(s grpc.ServiceRegistrar, srv DeviceManagerServiceServer) { + s.RegisterService(&DeviceManagerService_ServiceDesc, srv) +} + +func _DeviceManagerService_MapperRegister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MapperRegisterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DeviceManagerServiceServer).MapperRegister(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DeviceManagerService_MapperRegister_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DeviceManagerServiceServer).MapperRegister(ctx, req.(*MapperRegisterRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DeviceManagerService_ReportDeviceStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReportDeviceStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DeviceManagerServiceServer).ReportDeviceStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DeviceManagerService_ReportDeviceStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DeviceManagerServiceServer).ReportDeviceStatus(ctx, req.(*ReportDeviceStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// DeviceManagerService_ServiceDesc is the grpc.ServiceDesc for DeviceManagerService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var DeviceManagerService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "v1beta1.DeviceManagerService", + HandlerType: (*DeviceManagerServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "MapperRegister", + Handler: _DeviceManagerService_MapperRegister_Handler, + }, + { + MethodName: "ReportDeviceStatus", + Handler: _DeviceManagerService_ReportDeviceStatus_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "api.proto", +} + +const ( + DeviceMapperService_RegisterDevice_FullMethodName = "/v1beta1.DeviceMapperService/RegisterDevice" + DeviceMapperService_RemoveDevice_FullMethodName = "/v1beta1.DeviceMapperService/RemoveDevice" + DeviceMapperService_UpdateDevice_FullMethodName = "/v1beta1.DeviceMapperService/UpdateDevice" + DeviceMapperService_CreateDeviceModel_FullMethodName = "/v1beta1.DeviceMapperService/CreateDeviceModel" + DeviceMapperService_RemoveDeviceModel_FullMethodName = "/v1beta1.DeviceMapperService/RemoveDeviceModel" + DeviceMapperService_UpdateDeviceModel_FullMethodName = "/v1beta1.DeviceMapperService/UpdateDeviceModel" + DeviceMapperService_GetDevice_FullMethodName = "/v1beta1.DeviceMapperService/GetDevice" +) + +// DeviceMapperServiceClient is the client API for DeviceMapperService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type DeviceMapperServiceClient interface { + // RegisterDevice registers a device to the device mapper. + // Device manager registers a device instance with the information of device + // to the mapper through the interface of RegisterDevice. + // When the mapper gets the request of register with device information, + // it should add the device to the device list and connect to the real physical device via the specific protocol. + RegisterDevice(ctx context.Context, in *RegisterDeviceRequest, opts ...grpc.CallOption) (*RegisterDeviceResponse, error) + // RemoveDevice unregisters a device to the device mapper. + // Device manager unregisters a device instance with the name of device + // to the mapper through the interface of RemoveDevice. + // When the mapper gets the request of unregister with device name, + // it should remove the device from the device list and disconnect to the real physical device. + RemoveDevice(ctx context.Context, in *RemoveDeviceRequest, opts ...grpc.CallOption) (*RemoveDeviceResponse, error) + // UpdateDevice updates a device to the device mapper + // Device manager updates the information of a device used by the mapper + // through the interface of UpdateDevice. + // The information of a device includes the meta data and the status data of a device. + // When the mapper gets the request of updating with the information of a device, + // it should update the device of the device list and connect to the real physical device via the updated information. + UpdateDevice(ctx context.Context, in *UpdateDeviceRequest, opts ...grpc.CallOption) (*UpdateDeviceResponse, error) + // CreateDeviceModel creates a device model to the device mapper. + // Device manager sends the information of device model to the mapper + // through the interface of CreateDeviceModel. + // When the mapper gets the request of creating with the information of device model, + // it should create a new device model to the list of device models. + CreateDeviceModel(ctx context.Context, in *CreateDeviceModelRequest, opts ...grpc.CallOption) (*CreateDeviceModelResponse, error) + // RemoveDeviceModel remove a device model to the device mapper. + // Device manager sends the name of device model to the mapper + // through the interface of RemoveDeviceModel. + // When the mapper gets the request of removing with the name of device model, + // it should remove the device model to the list of device models. + RemoveDeviceModel(ctx context.Context, in *RemoveDeviceModelRequest, opts ...grpc.CallOption) (*RemoveDeviceModelResponse, error) + // UpdateDeviceModel update a device model to the device mapper. + // Device manager sends the information of device model to the mapper + // through the interface of UpdateDeviceModel. + // When the mapper gets the request of updating with the information of device model, + // it should update the device model to the list of device models. + UpdateDeviceModel(ctx context.Context, in *UpdateDeviceModelRequest, opts ...grpc.CallOption) (*UpdateDeviceModelResponse, error) + // GetDevice get the information of a device from the device mapper. + // Device sends the request of querying device information with the device name to the mapper + // through the interface of GetDevice. + // When the mapper gets the request of querying with the device name, + // it should return the device information. + GetDevice(ctx context.Context, in *GetDeviceRequest, opts ...grpc.CallOption) (*GetDeviceResponse, error) +} + +type deviceMapperServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewDeviceMapperServiceClient(cc grpc.ClientConnInterface) DeviceMapperServiceClient { + return &deviceMapperServiceClient{cc} +} + +func (c *deviceMapperServiceClient) RegisterDevice(ctx context.Context, in *RegisterDeviceRequest, opts ...grpc.CallOption) (*RegisterDeviceResponse, error) { + out := new(RegisterDeviceResponse) + err := c.cc.Invoke(ctx, DeviceMapperService_RegisterDevice_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *deviceMapperServiceClient) RemoveDevice(ctx context.Context, in *RemoveDeviceRequest, opts ...grpc.CallOption) (*RemoveDeviceResponse, error) { + out := new(RemoveDeviceResponse) + err := c.cc.Invoke(ctx, DeviceMapperService_RemoveDevice_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *deviceMapperServiceClient) UpdateDevice(ctx context.Context, in *UpdateDeviceRequest, opts ...grpc.CallOption) (*UpdateDeviceResponse, error) { + out := new(UpdateDeviceResponse) + err := c.cc.Invoke(ctx, DeviceMapperService_UpdateDevice_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *deviceMapperServiceClient) CreateDeviceModel(ctx context.Context, in *CreateDeviceModelRequest, opts ...grpc.CallOption) (*CreateDeviceModelResponse, error) { + out := new(CreateDeviceModelResponse) + err := c.cc.Invoke(ctx, DeviceMapperService_CreateDeviceModel_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *deviceMapperServiceClient) RemoveDeviceModel(ctx context.Context, in *RemoveDeviceModelRequest, opts ...grpc.CallOption) (*RemoveDeviceModelResponse, error) { + out := new(RemoveDeviceModelResponse) + err := c.cc.Invoke(ctx, DeviceMapperService_RemoveDeviceModel_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *deviceMapperServiceClient) UpdateDeviceModel(ctx context.Context, in *UpdateDeviceModelRequest, opts ...grpc.CallOption) (*UpdateDeviceModelResponse, error) { + out := new(UpdateDeviceModelResponse) + err := c.cc.Invoke(ctx, DeviceMapperService_UpdateDeviceModel_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *deviceMapperServiceClient) GetDevice(ctx context.Context, in *GetDeviceRequest, opts ...grpc.CallOption) (*GetDeviceResponse, error) { + out := new(GetDeviceResponse) + err := c.cc.Invoke(ctx, DeviceMapperService_GetDevice_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DeviceMapperServiceServer is the server API for DeviceMapperService service. +// All implementations must embed UnimplementedDeviceMapperServiceServer +// for forward compatibility +type DeviceMapperServiceServer interface { + // RegisterDevice registers a device to the device mapper. + // Device manager registers a device instance with the information of device + // to the mapper through the interface of RegisterDevice. + // When the mapper gets the request of register with device information, + // it should add the device to the device list and connect to the real physical device via the specific protocol. + RegisterDevice(context.Context, *RegisterDeviceRequest) (*RegisterDeviceResponse, error) + // RemoveDevice unregisters a device to the device mapper. + // Device manager unregisters a device instance with the name of device + // to the mapper through the interface of RemoveDevice. + // When the mapper gets the request of unregister with device name, + // it should remove the device from the device list and disconnect to the real physical device. + RemoveDevice(context.Context, *RemoveDeviceRequest) (*RemoveDeviceResponse, error) + // UpdateDevice updates a device to the device mapper + // Device manager updates the information of a device used by the mapper + // through the interface of UpdateDevice. + // The information of a device includes the meta data and the status data of a device. + // When the mapper gets the request of updating with the information of a device, + // it should update the device of the device list and connect to the real physical device via the updated information. + UpdateDevice(context.Context, *UpdateDeviceRequest) (*UpdateDeviceResponse, error) + // CreateDeviceModel creates a device model to the device mapper. + // Device manager sends the information of device model to the mapper + // through the interface of CreateDeviceModel. + // When the mapper gets the request of creating with the information of device model, + // it should create a new device model to the list of device models. + CreateDeviceModel(context.Context, *CreateDeviceModelRequest) (*CreateDeviceModelResponse, error) + // RemoveDeviceModel remove a device model to the device mapper. + // Device manager sends the name of device model to the mapper + // through the interface of RemoveDeviceModel. + // When the mapper gets the request of removing with the name of device model, + // it should remove the device model to the list of device models. + RemoveDeviceModel(context.Context, *RemoveDeviceModelRequest) (*RemoveDeviceModelResponse, error) + // UpdateDeviceModel update a device model to the device mapper. + // Device manager sends the information of device model to the mapper + // through the interface of UpdateDeviceModel. + // When the mapper gets the request of updating with the information of device model, + // it should update the device model to the list of device models. + UpdateDeviceModel(context.Context, *UpdateDeviceModelRequest) (*UpdateDeviceModelResponse, error) + // GetDevice get the information of a device from the device mapper. + // Device sends the request of querying device information with the device name to the mapper + // through the interface of GetDevice. + // When the mapper gets the request of querying with the device name, + // it should return the device information. + GetDevice(context.Context, *GetDeviceRequest) (*GetDeviceResponse, error) + mustEmbedUnimplementedDeviceMapperServiceServer() +} + +// UnimplementedDeviceMapperServiceServer must be embedded to have forward compatible implementations. +type UnimplementedDeviceMapperServiceServer struct { +} + +func (UnimplementedDeviceMapperServiceServer) RegisterDevice(context.Context, *RegisterDeviceRequest) (*RegisterDeviceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterDevice not implemented") +} +func (UnimplementedDeviceMapperServiceServer) RemoveDevice(context.Context, *RemoveDeviceRequest) (*RemoveDeviceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoveDevice not implemented") +} +func (UnimplementedDeviceMapperServiceServer) UpdateDevice(context.Context, *UpdateDeviceRequest) (*UpdateDeviceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateDevice not implemented") +} +func (UnimplementedDeviceMapperServiceServer) CreateDeviceModel(context.Context, *CreateDeviceModelRequest) (*CreateDeviceModelResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateDeviceModel not implemented") +} +func (UnimplementedDeviceMapperServiceServer) RemoveDeviceModel(context.Context, *RemoveDeviceModelRequest) (*RemoveDeviceModelResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoveDeviceModel not implemented") +} +func (UnimplementedDeviceMapperServiceServer) UpdateDeviceModel(context.Context, *UpdateDeviceModelRequest) (*UpdateDeviceModelResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateDeviceModel not implemented") +} +func (UnimplementedDeviceMapperServiceServer) GetDevice(context.Context, *GetDeviceRequest) (*GetDeviceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetDevice not implemented") +} +func (UnimplementedDeviceMapperServiceServer) mustEmbedUnimplementedDeviceMapperServiceServer() {} + +// UnsafeDeviceMapperServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to DeviceMapperServiceServer will +// result in compilation errors. +type UnsafeDeviceMapperServiceServer interface { + mustEmbedUnimplementedDeviceMapperServiceServer() +} + +func RegisterDeviceMapperServiceServer(s grpc.ServiceRegistrar, srv DeviceMapperServiceServer) { + s.RegisterService(&DeviceMapperService_ServiceDesc, srv) +} + +func _DeviceMapperService_RegisterDevice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RegisterDeviceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DeviceMapperServiceServer).RegisterDevice(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DeviceMapperService_RegisterDevice_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DeviceMapperServiceServer).RegisterDevice(ctx, req.(*RegisterDeviceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DeviceMapperService_RemoveDevice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveDeviceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DeviceMapperServiceServer).RemoveDevice(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DeviceMapperService_RemoveDevice_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DeviceMapperServiceServer).RemoveDevice(ctx, req.(*RemoveDeviceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DeviceMapperService_UpdateDevice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateDeviceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DeviceMapperServiceServer).UpdateDevice(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DeviceMapperService_UpdateDevice_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DeviceMapperServiceServer).UpdateDevice(ctx, req.(*UpdateDeviceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DeviceMapperService_CreateDeviceModel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateDeviceModelRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DeviceMapperServiceServer).CreateDeviceModel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DeviceMapperService_CreateDeviceModel_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DeviceMapperServiceServer).CreateDeviceModel(ctx, req.(*CreateDeviceModelRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DeviceMapperService_RemoveDeviceModel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveDeviceModelRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DeviceMapperServiceServer).RemoveDeviceModel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DeviceMapperService_RemoveDeviceModel_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DeviceMapperServiceServer).RemoveDeviceModel(ctx, req.(*RemoveDeviceModelRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DeviceMapperService_UpdateDeviceModel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateDeviceModelRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DeviceMapperServiceServer).UpdateDeviceModel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DeviceMapperService_UpdateDeviceModel_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DeviceMapperServiceServer).UpdateDeviceModel(ctx, req.(*UpdateDeviceModelRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DeviceMapperService_GetDevice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetDeviceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DeviceMapperServiceServer).GetDevice(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DeviceMapperService_GetDevice_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DeviceMapperServiceServer).GetDevice(ctx, req.(*GetDeviceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// DeviceMapperService_ServiceDesc is the grpc.ServiceDesc for DeviceMapperService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var DeviceMapperService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "v1beta1.DeviceMapperService", + HandlerType: (*DeviceMapperServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "RegisterDevice", + Handler: _DeviceMapperService_RegisterDevice_Handler, + }, + { + MethodName: "RemoveDevice", + Handler: _DeviceMapperService_RemoveDevice_Handler, + }, + { + MethodName: "UpdateDevice", + Handler: _DeviceMapperService_UpdateDevice_Handler, + }, + { + MethodName: "CreateDeviceModel", + Handler: _DeviceMapperService_CreateDeviceModel_Handler, + }, + { + MethodName: "RemoveDeviceModel", + Handler: _DeviceMapperService_RemoveDeviceModel_Handler, + }, + { + MethodName: "UpdateDeviceModel", + Handler: _DeviceMapperService_UpdateDeviceModel_Handler, + }, + { + MethodName: "GetDevice", + Handler: _DeviceMapperService_GetDevice_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "api.proto", +} diff --git a/mappers/usbcamera-dmi/pkg/global/global.go b/mappers/usbcamera-dmi/pkg/global/global.go new file mode 100755 index 00000000..7d7c6ad5 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/global/global.go @@ -0,0 +1,58 @@ +package global + +import ( + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/config" +) + +// DevPanel defined operations on devices, manage the lifecycle of devices +type DevPanel interface { + // DevStart start device to collect/push/save data to edgecore/app/database + DevStart() + // DevInit get device info by dmi interface + DevInit(cfg *config.Config) error + // UpdateDev update device's config and restart the device + UpdateDev(model *common.DeviceModel, device *common.DeviceInstance, protocol *common.ProtocolConfig) + // UpdateDevTwins update device twin's config and restart the device + UpdateDevTwins(deviceID string, twins []common.Twin) error + // DealDeviceTwinGet get device's twin data + DealDeviceTwinGet(deviceID string, twinName string) (interface{}, error) + // GetDevice get device's instance info + GetDevice(deviceID string) (interface{}, error) + // RemoveDevice stop device and remove device + RemoveDevice(deviceID string) error + // GetModel get model's info + GetModel(modelName string) (common.DeviceModel, error) + // UpdateModel update model in map only + UpdateModel(model *common.DeviceModel) + // RemoveModel remove model in map only + RemoveModel(modelName string) + // GetTwinResult get device's property value and datatype + GetTwinResult(deviceID string, twinName string) (string, string, error) +} + +// DataPanel defined push method, parse the push operation in CRD and execute it +type DataPanel interface { + // TODO add more interface + + // InitPushMethod initialization operation before push + InitPushMethod() error + // Push implement push operation + Push(data *common.DataModel) +} + +// DataBaseClient defined database interface, save data and provide data to REST API +type DataBaseClient interface { + // TODO add more interface + + InitDbClient() error + CloseSession() + + AddData(data *common.DataModel) + + GetDataByDeviceName(deviceName string) ([]*common.DataModel, error) + GetPropertyDataByDeviceName(deviceName string, propertyData string) ([]*common.DataModel, error) + GetDataByTimeRange(start int64, end int64) ([]*common.DataModel, error) + + DeleteDataByTimeRange(start int64, end int64) ([]*common.DataModel, error) +} diff --git a/mappers/usbcamera-dmi/pkg/grpcserver/device.go b/mappers/usbcamera-dmi/pkg/grpcserver/device.go new file mode 100755 index 00000000..daafd485 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/grpcserver/device.go @@ -0,0 +1,159 @@ +package grpcserver + +import ( + "context" + "errors" + "fmt" + "time" + + "k8s.io/klog/v2" + "reflect" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" + dmiapi "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/dmi-api" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/util/parse" +) + +func (s *Server) RegisterDevice(ctx context.Context, request *dmiapi.RegisterDeviceRequest) (*dmiapi.RegisterDeviceResponse, error) { + klog.V(3).Info("RegisterDevice") + device := request.GetDevice() + if device == nil { + return nil, errors.New("device is nil") + } + if _, err := s.devPanel.GetDevice(device.Name); err == nil { + // The device has been registered + return &dmiapi.RegisterDeviceResponse{DeviceName: device.Name}, nil + } + + var model common.DeviceModel + var err error + for i := 0; i < 3; i++ { + model, err = s.devPanel.GetModel(device.Spec.DeviceModelReference) + if err != nil { + klog.Errorf("deviceModel %s not found, err: %s", device.Spec.DeviceModelReference, err) + time.Sleep(1 * time.Second) + } else { + break + } + } + if err != nil { + return nil, fmt.Errorf("deviceModel %s not found, err: %s", device.Spec.DeviceModelReference, err) + } + protocol, err := parse.BuildProtocolFromGrpc(device) + if err != nil { + return nil, fmt.Errorf("parse device %s protocol failed, err: %s", device.Name, err) + } + klog.Infof("model: %+v", model) + deviceInstance, err := parse.ParseDeviceFromGrpc(device, &model) + + if err != nil { + return nil, fmt.Errorf("parse device %s instance failed, err: %s", device.Name, err) + } + + deviceInstance.PProtocol = protocol + s.devPanel.UpdateDev(&model, deviceInstance, &protocol) + + return &dmiapi.RegisterDeviceResponse{DeviceName: device.Name}, nil +} + +func (s *Server) RemoveDevice(ctx context.Context, request *dmiapi.RemoveDeviceRequest) (*dmiapi.RemoveDeviceResponse, error) { + if request.GetDeviceName() == "" { + return nil, errors.New("device name is nil") + } + + return &dmiapi.RemoveDeviceResponse{}, s.devPanel.RemoveDevice(request.GetDeviceName()) +} + +func (s *Server) UpdateDevice(ctx context.Context, request *dmiapi.UpdateDeviceRequest) (*dmiapi.UpdateDeviceResponse, error) { + klog.V(3).Info("UpdateDevice") + device := request.GetDevice() + if device == nil { + return nil, errors.New("device is nil") + } + + model, err := s.devPanel.GetModel(device.Spec.DeviceModelReference) + if err != nil { + return nil, fmt.Errorf("deviceModel %s not found, err: %s", device.Spec.DeviceModelReference, err) + } + protocol, err := parse.BuildProtocolFromGrpc(device) + if err != nil { + return nil, fmt.Errorf("parse device %s protocol failed, err: %s", device.Name, err) + } + + klog.V(3).Infof("model: %+v", model) + deviceInstance, err := parse.ParseDeviceFromGrpc(device, &model) + if err != nil { + return nil, fmt.Errorf("parse device %s instance failed, err: %s", device.Name, err) + } + deviceInstance.PProtocol = protocol + + s.devPanel.UpdateDev(&model, deviceInstance, &protocol) + + return &dmiapi.UpdateDeviceResponse{}, nil +} + +func (s *Server) CreateDeviceModel(ctx context.Context, request *dmiapi.CreateDeviceModelRequest) (*dmiapi.CreateDeviceModelResponse, error) { + deviceModel := request.GetModel() + klog.Infof("start create deviceModel: %v", deviceModel.Name) + if deviceModel == nil { + return nil, errors.New("deviceModel is nil") + } + + model := parse.ParseDeviceModelFromGrpc(deviceModel) + + s.devPanel.UpdateModel(&model) + + klog.Infof("create deviceModel done: %v", deviceModel.Name) + + return &dmiapi.CreateDeviceModelResponse{DeviceModelName: deviceModel.Name}, nil +} + +func (s *Server) UpdateDeviceModel(ctx context.Context, request *dmiapi.UpdateDeviceModelRequest) (*dmiapi.UpdateDeviceModelResponse, error) { + deviceModel := request.GetModel() + if deviceModel == nil { + return nil, errors.New("deviceModel is nil") + } + if _, err := s.devPanel.GetModel(deviceModel.Name); err != nil { + return nil, fmt.Errorf("update deviceModel %s failed, not existed", deviceModel.Name) + } + + model := parse.ParseDeviceModelFromGrpc(deviceModel) + + s.devPanel.UpdateModel(&model) + + return &dmiapi.UpdateDeviceModelResponse{}, nil +} + +func (s *Server) RemoveDeviceModel(ctx context.Context, request *dmiapi.RemoveDeviceModelRequest) (*dmiapi.RemoveDeviceModelResponse, error) { + s.devPanel.RemoveModel(request.ModelName) + + return &dmiapi.RemoveDeviceModelResponse{}, nil +} + +func (s *Server) GetDevice(ctx context.Context, request *dmiapi.GetDeviceRequest) (*dmiapi.GetDeviceResponse, error) { + if request.GetDeviceName() == "" { + return nil, errors.New("device name is nil") + } + + device, err := s.devPanel.GetDevice(request.GetDeviceName()) + if err != nil { + return nil, err + } + res := &dmiapi.GetDeviceResponse{ + Device: &dmiapi.Device{ + Status: &dmiapi.DeviceStatus{}, + }, + } + deviceValue := reflect.ValueOf(device) + twinsValue := deviceValue.FieldByName("Instance").FieldByName("Twins") + if !twinsValue.IsValid() { + return nil, fmt.Errorf("twins field not found") + } + twins, err := parse.ConvTwinsToGrpc(twinsValue.Interface().([]common.Twin)) + if err != nil { + return nil, err + } + res.Device.Status.Twins = twins + //res.Device.Status.State = common.DEVSTOK + return res, nil +} diff --git a/mappers/usbcamera-dmi/pkg/grpcserver/server.go b/mappers/usbcamera-dmi/pkg/grpcserver/server.go new file mode 100755 index 00000000..ad511dbf --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/grpcserver/server.go @@ -0,0 +1,79 @@ +package grpcserver + +import ( + "fmt" + "net" + "os" + + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" + "k8s.io/klog/v2" + + dmiapi "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/dmi-api" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/global" +) + +type Config struct { + SockPath string `json:"sock_path"` + Protocol string `json:"protocol"` +} + +type Server struct { + dmiapi.UnimplementedDeviceMapperServiceServer + lis net.Listener + cfg Config + devPanel global.DevPanel +} + +func NewServer(cfg Config, devPanel global.DevPanel) Server { + s := Server{cfg: cfg} + s.devPanel = devPanel + return s +} + +func (s *Server) Start() error { + klog.Infof("uds socket path: %s", s.cfg.SockPath) + err := initSock(s.cfg.SockPath) + if err != nil { + klog.Fatalf("failed to remove uds socket with err: %v", err) + return err + } + + s.lis, err = net.Listen("unix", s.cfg.SockPath) + if err != nil { + klog.Fatalf("failed to remove uds socket with err: %v", err) + return err + } + grpcServer := grpc.NewServer() + dmiapi.RegisterDeviceMapperServiceServer(grpcServer, s) + reflection.Register(grpcServer) + klog.V(2).Info("start grpc server") + return grpcServer.Serve(s.lis) +} + +func (s *Server) Stop() { + err := s.lis.Close() + if err != nil { + return + } + err = os.Remove(s.cfg.SockPath) + if err != nil { + return + } +} + +func initSock(sockPath string) error { + klog.V(2).Infof("init uds socket: %s", sockPath) + _, err := os.Stat(sockPath) + if err == nil { + err = os.Remove(sockPath) + if err != nil { + return err + } + return nil + } else if os.IsNotExist(err) { + return nil + } else { + return fmt.Errorf("fail to stat uds socket path") + } +} diff --git a/mappers/usbcamera-dmi/pkg/httpserver/callback.go b/mappers/usbcamera-dmi/pkg/httpserver/callback.go new file mode 100755 index 00000000..b9f1d757 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/httpserver/callback.go @@ -0,0 +1,86 @@ +package httpserver + +import ( + "fmt" + "net/http" + "reflect" + "strings" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" +) + +func (rs *RestServer) Ping(writer http.ResponseWriter, request *http.Request) { + response := &PingResponse{ + BaseResponse: NewBaseResponse(http.StatusOK), + Message: fmt.Sprintf("This is %s API, the server is running normally.", APIVersion), + } + rs.sendResponse(writer, request, response, http.StatusOK) +} + +func (rs *RestServer) DeviceRead(writer http.ResponseWriter, request *http.Request) { + urlItem := strings.Split(request.URL.Path, "/") + deviceName := urlItem[len(urlItem)-2] + propertyName := urlItem[len(urlItem)-1] + res, dataType, err := rs.devPanel.GetTwinResult(urlItem[len(urlItem)-2], urlItem[len(urlItem)-1]) + if err != nil { + http.Error(writer, fmt.Sprintf("Get device data error: %v", err), http.StatusInternalServerError) + } else { + response := &DeviceReadResponse{ + BaseResponse: NewBaseResponse(http.StatusOK), + Data: common.NewDataModel( + deviceName, + propertyName, + common.WithValue(res), + common.WithType(dataType), + ), + } + rs.sendResponse(writer, request, response, http.StatusOK) + } +} + +func (rs *RestServer) MetaGetModel(writer http.ResponseWriter, request *http.Request) { + urlItem := strings.Split(request.URL.Path, "/") + deviceName := urlItem[len(urlItem)-1] + device, err := rs.devPanel.GetDevice(deviceName) + if err != nil { + http.Error(writer, fmt.Sprintf("Get device error: %v", err), http.StatusInternalServerError) + return + } + driverInstancePtr := reflect.ValueOf(device) + if driverInstancePtr.IsNil() { + http.Error(writer, fmt.Sprintf("Get device error: %v", err), http.StatusInternalServerError) + return + } + instance := driverInstancePtr.Elem().FieldByName("Instance") + if instance.IsValid() { + instance, ok := instance.Interface().(common.DeviceInstance) + if ok { + model, err := rs.devPanel.GetModel(instance.Model) + if err != nil { + http.Error(writer, fmt.Sprintf("Get device model error: %v", err), http.StatusInternalServerError) + } + response := &MetaGetModelResponse{ + BaseResponse: NewBaseResponse(http.StatusOK), + DeviceModel: &model, + } + rs.sendResponse(writer, request, response, http.StatusOK) + } else { + http.Error(writer, fmt.Sprintf("Get device instance error: %v", err), http.StatusInternalServerError) + } + } else { + http.Error(writer, fmt.Sprintf("Get device instance error: %v", err), http.StatusInternalServerError) + } + +} + +func (rs *RestServer) DataBaseGetDataByID(writer http.ResponseWriter, request *http.Request) { + if rs.databaseClient == nil { + http.Error(writer, "The database is not enabled. Please configure mapper and try again", http.StatusServiceUnavailable) + return + } + response := &DataBaseResponse{ + BaseResponse: NewBaseResponse(http.StatusOK), + Data: nil, + } + rs.sendResponse(writer, request, response, http.StatusOK) +} diff --git a/mappers/usbcamera-dmi/pkg/httpserver/responsetype.go b/mappers/usbcamera-dmi/pkg/httpserver/responsetype.go new file mode 100755 index 00000000..fb8d43dc --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/httpserver/responsetype.go @@ -0,0 +1,45 @@ +package httpserver + +import ( + "time" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" +) + +// BaseResponse the base response struct of all response +type BaseResponse struct { + APIVersion string `json:"apiVersion"` + StatusCode int `json:"statusCode"` + TimeStamp string `json:"timeStamp"` +} + +// NewBaseResponse get BaseResponse by statusCode +func NewBaseResponse(statusCode int) *BaseResponse { + return &BaseResponse{ + APIVersion: APIVersion, + StatusCode: statusCode, + TimeStamp: time.Now().Format(time.RFC3339), + } +} + +type PingResponse struct { + *BaseResponse + Message string +} + +type DeviceReadResponse struct { + *BaseResponse + Data *common.DataModel +} + +type MetaGetModelResponse struct { + *BaseResponse + *common.DeviceModel +} + +// DataBaseResponse just for test +type DataBaseResponse struct { + // TODO DataBase API need to add + *BaseResponse + Data []common.DataModel +} diff --git a/mappers/usbcamera-dmi/pkg/httpserver/restapi.go b/mappers/usbcamera-dmi/pkg/httpserver/restapi.go new file mode 100755 index 00000000..c379d570 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/httpserver/restapi.go @@ -0,0 +1,46 @@ +package httpserver + +// API path +const ( + // APIVersion description API version + APIVersion = "v1" + // APIBase to build RESTful API + APIBase = "/api/" + APIVersion + + // APIPing ping API that get server status + APIPing = APIBase + "/ping" + + // APIDeviceRoute to build device RESTful API + APIDeviceRoute = APIBase + "/device" + // APIDeviceReadRoute API that read device's property + APIDeviceReadRoute = APIDeviceRoute + "/" + DeviceID + "/" + PropertyName + + // APIMetaRoute to build meta RESTful API + APIMetaRoute = APIBase + "/meta" + // APIMetaGetModelRoute API that get device model by device id + APIMetaGetModelRoute = APIMetaRoute + "/model" + "/" + DeviceID + + // APIDataBaseRoute to build database RESTful API + APIDataBaseRoute = APIBase + "/database" + // APIDataBaseGetDataByID API that get data by device id + APIDataBaseGetDataByID = APIDataBaseRoute + "/" + DeviceID +) + +// API field pattern +const ( + // DeviceID pattern for deviceID + DeviceID = "{id}" + // PropertyName pattern for property + PropertyName = "{property}" +) + +// Response Header +const ( + // ContentType content header Key + ContentType = "Content-Type" + // ContentTypeJSON content type is json + ContentTypeJSON = "application/json" + + // CorrelationHeader correlation header key + CorrelationHeader = "X-Correlation-ID" +) diff --git a/mappers/usbcamera-dmi/pkg/httpserver/router.go b/mappers/usbcamera-dmi/pkg/httpserver/router.go new file mode 100755 index 00000000..269b671c --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/httpserver/router.go @@ -0,0 +1,17 @@ +package httpserver + +import "net/http" + +func (rs *RestServer) InitRouter() { + // Common + rs.Router.HandleFunc(APIPing, rs.Ping).Methods(http.MethodGet) + + // Device + rs.Router.HandleFunc(APIDeviceReadRoute, rs.DeviceRead).Methods(http.MethodGet) + + // Meta + rs.Router.HandleFunc(APIMetaGetModelRoute, rs.MetaGetModel).Methods(http.MethodGet) + + // DataBase + rs.Router.HandleFunc(APIDataBaseGetDataByID, rs.DataBaseGetDataByID).Methods(http.MethodGet) +} diff --git a/mappers/usbcamera-dmi/pkg/httpserver/server.go b/mappers/usbcamera-dmi/pkg/httpserver/server.go new file mode 100755 index 00000000..e4479e71 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/httpserver/server.go @@ -0,0 +1,170 @@ +package httpserver + +import ( + "crypto/tls" + "crypto/x509" + "encoding/json" + "io/ioutil" + "net/http" + "time" + + "github.com/gorilla/mux" + "k8s.io/klog/v2" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/global" +) + +type RestServer struct { + IP string + Port string + WriteTimeout time.Duration + ReadTimeout time.Duration + CertFilePath string + KeyFilePath string + CaCertFilePath string + server *http.Server + Router *mux.Router + devPanel global.DevPanel + databaseClient global.DataBaseClient +} + +type Option func(server *RestServer) + +func NewRestServer(devPanel global.DevPanel, options ...Option) *RestServer { + rest := &RestServer{ + IP: "0.0.0.0", + Port: "7777", + Router: mux.NewRouter(), + WriteTimeout: 10 * time.Second, + ReadTimeout: 10 * time.Second, + devPanel: devPanel, + } + for _, option := range options { + option(rest) + } + return rest +} + +func (rs *RestServer) StartServer() { + rs.InitRouter() + rs.server = &http.Server{ + Addr: rs.IP + ":" + rs.Port, + WriteTimeout: rs.WriteTimeout, + ReadTimeout: rs.ReadTimeout, + Handler: rs.Router, + } + if rs.CaCertFilePath == "" && (rs.KeyFilePath == "" || rs.CertFilePath == "") { + // insecure + klog.V(3).Info("Insecure communication, skipping server verification") + err := rs.server.ListenAndServe() + if err != nil { + klog.Errorf("insecure http server error: %v", err) + return + } + } else if rs.CaCertFilePath == "" && rs.KeyFilePath != "" && rs.CertFilePath != "" { + // tls + klog.V(3).Info("tls communication, https server start") + err := rs.server.ListenAndServeTLS(rs.CertFilePath, rs.KeyFilePath) + if err != nil { + klog.Errorf("tls http server error: %v", err) + return + } + } else if rs.CaCertFilePath != "" && rs.KeyFilePath != "" && rs.CertFilePath != "" { + // mtls + klog.V(3).Info("mtls communication, please provide client-key and client-cert to access service") + // Configure the server to trust TLS client cert issued by your CA. + certPool := x509.NewCertPool() + if caCertPEM, err := ioutil.ReadFile(rs.CaCertFilePath); err != nil { + klog.Errorf("Error loading ca certificate file: %v", err) + return + } else if ok := certPool.AppendCertsFromPEM(caCertPEM); !ok { + klog.Error("invalid cert in CA PEM") + return + } + tlsConfig := &tls.Config{ + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: certPool, + } + rs.server.TLSConfig = tlsConfig + err := rs.server.ListenAndServeTLS(rs.CertFilePath, rs.KeyFilePath) + if err != nil { + klog.Errorf("tls http server error: %v", err) + return + } + } else { + klog.Error("the certificate file provided is incomplete or does not match") + } +} + +// sendResponse build response and put response's payload to writer +func (rs *RestServer) sendResponse( + writer http.ResponseWriter, + request *http.Request, + response interface{}, + statusCode int) { + + correlationID := request.Header.Get(CorrelationHeader) + if correlationID != "" { + writer.Header().Set(CorrelationHeader, correlationID) + } + writer.Header().Set(ContentType, ContentTypeJSON) + writer.WriteHeader(statusCode) + data, err := json.Marshal(response) + if err != nil { + klog.Errorf("marshal %s response error: %v", request.URL.Path, err) + http.Error(writer, err.Error(), http.StatusInternalServerError) + } + _, err = writer.Write(data) + if err != nil { + klog.Errorf("write %s response error: %v", request.URL.Path, err) + http.Error(writer, err.Error(), http.StatusInternalServerError) + } +} + +func WithIP(ip string) Option { + return func(server *RestServer) { + server.IP = ip + } +} + +func WithPort(port string) Option { + return func(server *RestServer) { + server.Port = port + } +} + +func WithWriteTimeout(timeout time.Duration) Option { + return func(server *RestServer) { + server.WriteTimeout = timeout + } +} + +func WithReadTimeout(timeout time.Duration) Option { + return func(server *RestServer) { + server.ReadTimeout = timeout + } +} + +func WithCertFile(certPath string) Option { + return func(server *RestServer) { + server.CertFilePath = certPath + } +} + +func WithKeyFile(keyFilePath string) Option { + return func(server *RestServer) { + server.KeyFilePath = keyFilePath + } +} + +func WithCaCertFile(caCertPath string) Option { + return func(server *RestServer) { + server.CaCertFilePath = caCertPath + } +} + +func WithDbClient(dbClient global.DataBaseClient) Option { + return func(server *RestServer) { + server.databaseClient = dbClient + } +} diff --git a/mappers/usbcamera-dmi/pkg/util/grpcclient/config.go b/mappers/usbcamera-dmi/pkg/util/grpcclient/config.go new file mode 100755 index 00000000..cfc68a25 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/util/grpcclient/config.go @@ -0,0 +1,12 @@ +package grpcclient + +import ( + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/config" +) + +var cfg *config.Config + +func Init(c *config.Config) { + cfg = &config.Config{} + cfg = c +} diff --git a/mappers/usbcamera-dmi/pkg/util/grpcclient/register.go b/mappers/usbcamera-dmi/pkg/util/grpcclient/register.go new file mode 100755 index 00000000..e3ee6b25 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/util/grpcclient/register.go @@ -0,0 +1,60 @@ +package grpcclient + +import ( + "context" + "fmt" + "net" + "time" + + "google.golang.org/grpc" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/config" + dmiapi "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/dmi-api" +) + +// RegisterMapper if withData is true, edgecore will send device and model list. +func RegisterMapper(cfg *config.Config, withData bool) ([]*dmiapi.Device, []*dmiapi.DeviceModel, error) { + // connect grpc server + conn, err := grpc.Dial(cfg.Common.EdgeCoreSock, + grpc.WithInsecure(), + grpc.WithBlock(), + grpc.WithContextDialer( + func(ctx context.Context, s string) (net.Conn, error) { + unixAddress, err := net.ResolveUnixAddr("unix", cfg.Common.EdgeCoreSock) + if err != nil { + return nil, err + } + return net.DialUnix("unix", nil, unixAddress) + }, + ), + ) + if err != nil { + return nil, nil, fmt.Errorf("did not connect: %v", err) + } + defer conn.Close() + + // init Greeter client + c := dmiapi.NewDeviceManagerServiceClient(conn) + + // init ctx,set timeout + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + resp, err := c.MapperRegister(ctx, &dmiapi.MapperRegisterRequest{ + WithData: withData, + Mapper: &dmiapi.MapperInfo{ + Name: cfg.Common.Name, + Version: cfg.Common.Version, + ApiVersion: cfg.Common.APIVersion, + Protocol: cfg.Common.Protocol, + Address: []byte(cfg.GrpcServer.SocketPath), + State: common.DEVSTOK, + }, + }) + if err != nil { + return nil, nil, err + } + + return resp.DeviceList, resp.ModelList, err +} diff --git a/mappers/usbcamera-dmi/pkg/util/grpcclient/report.go b/mappers/usbcamera-dmi/pkg/util/grpcclient/report.go new file mode 100755 index 00000000..1c9ce292 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/util/grpcclient/report.go @@ -0,0 +1,43 @@ +package grpcclient + +import ( + "context" + "fmt" + "net" + "time" + + "google.golang.org/grpc" + + dmiapi "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/dmi-api" +) + +// ReportDeviceStatus report device status to edgecore +func ReportDeviceStatus(request *dmiapi.ReportDeviceStatusRequest) error { + conn, err := grpc.Dial(cfg.Common.EdgeCoreSock, + grpc.WithInsecure(), + grpc.WithBlock(), + grpc.WithContextDialer( + func(ctx context.Context, s string) (net.Conn, error) { + unixAddress, err := net.ResolveUnixAddr("unix", cfg.Common.EdgeCoreSock) + if err != nil { + return nil, err + } + return net.DialUnix("unix", nil, unixAddress) + }, + ), + ) + if err != nil { + return fmt.Errorf("did not connect: %v", err) + } + defer conn.Close() + + // init Greeter client + c := dmiapi.NewDeviceManagerServiceClient(conn) + + // init context,set timeout + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + _, err = c.ReportDeviceStatus(ctx, request) + return err +} diff --git a/mappers/usbcamera-dmi/pkg/util/parse/grpc.go b/mappers/usbcamera-dmi/pkg/util/parse/grpc.go new file mode 100755 index 00000000..0a920a4a --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/util/parse/grpc.go @@ -0,0 +1,264 @@ +package parse + +import ( + "encoding/json" + "errors" + "k8s.io/klog/v2" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" + dmiapi "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/dmi-api" +) + +type TwinResultResponse struct { + PropertyName string `json:"property_name"` + Payload []byte `json:"payload"` +} + +func getProtocolNameFromGrpc(device *dmiapi.Device) (string, error) { + + return device.Spec.Protocol.ProtocolName, nil +} + +func getPushMethodFromGrpc(visitor *dmiapi.DeviceProperty) (string, error) { + // TODO add more push method + if visitor.PushMethod.Http != nil { + return "http", nil + } + if visitor.PushMethod.Mqtt != nil { + return "mqtt", nil + } + return "", nil +} + +func getDBMethodFromGrpc(visitor *dmiapi.DeviceProperty) (string, error) { + // TODO add more dbMethod + if visitor.PushMethod.DBMethod.Influxdb2 != nil { + return "influx", nil + } + return "", errors.New("can not parse dbMethod") +} + +func BuildProtocolFromGrpc(device *dmiapi.Device) (common.ProtocolConfig, error) { + protocolName, err := getProtocolNameFromGrpc(device) + if err != nil { + return common.ProtocolConfig{}, err + } + + var protocolConfig []byte + + customizedProtocol := make(map[string]interface{}) + customizedProtocol["protocolName"] = protocolName + if device.Spec.Protocol.ConfigData != nil { + recvAdapter := make(map[string]interface{}) + for k, v := range device.Spec.Protocol.ConfigData.Data { + value, err := common.DecodeAnyValue(v) + if err != nil { + continue + } + recvAdapter[k] = value + } + customizedProtocol["configData"] = recvAdapter + } + protocolConfig, err = json.Marshal(customizedProtocol) + if err != nil { + return common.ProtocolConfig{}, err + } + + return common.ProtocolConfig{ + ProtocolName: protocolName, + ConfigData: protocolConfig, + }, nil +} + +func buildTwinsFromGrpc(device *dmiapi.Device) []common.Twin { + if len(device.Spec.Properties) == 0 { + return nil + } + res := make([]common.Twin, 0, len(device.Spec.Properties)) + for _, property := range device.Spec.Properties { + cur := common.Twin{ + PropertyName: property.Name, + ObservedDesired: common.TwinProperty{ + Value: property.Desired.Value, + Metadata: common.Metadata{ + Timestamp: property.Desired.Metadata["timestamp"], + Type: property.Desired.Metadata["type"], + }, + }, + } + res = append(res, cur) + } + return res +} + +func buildPropertiesFromGrpc(device *dmiapi.Device) []common.DeviceProperty { + if len(device.Spec.Properties) == 0 { + return nil + } + protocolName, err := getProtocolNameFromGrpc(device) + if err != nil { + return nil + } + res := make([]common.DeviceProperty, 0, len(device.Spec.Properties)) + klog.V(3).Infof("In buildPropertiesFromGrpc, PropertyVisitors = %v", device.Spec.Properties) + for _, pptv := range device.Spec.Properties { + + // get visitorConfig filed by grpc device instance + var visitorConfig []byte + recvAdapter := make(map[string]interface{}) + for k, v := range pptv.Visitors.ConfigData.Data { + value, err := common.DecodeAnyValue(v) + if err != nil { + continue + } + recvAdapter[k] = value + } + customizedProtocol := make(map[string]interface{}) + customizedProtocol["protocolName"] = pptv.Visitors.ProtocolName + customizedProtocol["configData"] = recvAdapter + visitorConfig, err = json.Marshal(customizedProtocol) + if err != nil { + klog.Errorf("err: %+v", err) + return nil + } + + // get dbMethod filed by grpc device instance + var dbMethodName string + var dbconfig common.DBConfig + var pushMethod []byte + var pushMethodName string + if pptv.PushMethod != nil { + if pptv.PushMethod.DBMethod != nil { + dbMethodName, err = getDBMethodFromGrpc(pptv) + if err != nil { + klog.Errorf("err: %+v", err) + return nil + } + switch dbMethodName { + case "influx": + clientconfig, err := json.Marshal(pptv.PushMethod.DBMethod.Influxdb2.Influxdb2ClientConfig) + if err != nil { + klog.Errorf("err: %+v", err) + return nil + } + dataconfig, err := json.Marshal(pptv.PushMethod.DBMethod.Influxdb2.Influxdb2DataConfig) + if err != nil { + klog.Errorf("err: %+v", err) + return nil + } + dbconfig = common.DBConfig{ + Influxdb2ClientConfig: clientconfig, + Influxdb2DataConfig: dataconfig, + } + } + } + // get pushMethod filed by grpc device instance + pushMethodName, err = getPushMethodFromGrpc(pptv) + if err != nil { + klog.Errorf("err: %+v", err) + return nil + } + switch pushMethodName { + case "http": + pushMethod, err = json.Marshal(pptv.PushMethod.Http) + if err != nil { + klog.Errorf("err: %+v", err) + return nil + } + case "mqtt": + pushMethod, err = json.Marshal(pptv.PushMethod.Mqtt) + if err != nil { + klog.Errorf("err: %+v", err) + return nil + } + } + } + + // get the final Properties + cur := common.DeviceProperty{ + Name: pptv.GetName(), + PropertyName: pptv.GetName(), + ModelName: device.Spec.DeviceModelReference, + CollectCycle: pptv.GetCollectCycle(), + ReportCycle: pptv.GetReportCycle(), + ReportToCloud: pptv.GetReportToCloud(), + Protocol: protocolName, + Visitors: visitorConfig, + PushMethod: common.PushMethodConfig{ + MethodName: pushMethodName, + MethodConfig: pushMethod, + DBMethod: common.DBMethodConfig{ + DBMethodName: dbMethodName, + DBConfig: dbconfig, + }, + }, + } + res = append(res, cur) + + } + return res +} + +func ParseDeviceModelFromGrpc(model *dmiapi.DeviceModel) common.DeviceModel { + cur := common.DeviceModel{ + Name: model.GetName(), + } + if model.GetSpec() == nil || len(model.GetSpec().GetProperties()) == 0 { + return cur + } + properties := make([]common.ModelProperty, 0, len(model.Spec.Properties)) + for _, property := range model.Spec.Properties { + p := common.ModelProperty{ + Name: property.GetName(), + Description: property.GetDescription(), + DataType: property.Type, + AccessMode: property.AccessMode, + Minimum: property.Minimum, + Maximum: property.Maximum, + Unit: property.Unit, + } + properties = append(properties, p) + } + cur.Properties = properties + return cur +} + +func ParseDeviceFromGrpc(device *dmiapi.Device, commonModel *common.DeviceModel) (*common.DeviceInstance, error) { + + protocolName, err := getProtocolNameFromGrpc(device) + if err != nil { + return nil, err + } + instance := &common.DeviceInstance{ + ID: device.GetName(), + Name: device.GetName(), + ProtocolName: protocolName + "-" + device.GetName(), + Model: device.Spec.DeviceModelReference, + Twins: buildTwinsFromGrpc(device), + Properties: buildPropertiesFromGrpc(device), + } + // copy Properties to twin + propertiesMap := make(map[string]common.DeviceProperty) + for i := 0; i < len(instance.Properties); i++ { + if commonModel == nil { + klog.Errorf("commonModel == nil") + continue + } + + // parse the content of the modelproperty field into instance + for _, property := range commonModel.Properties { + if property.Name == instance.Properties[i].PropertyName { + instance.Properties[i].PProperty = property + break + } + } + propertiesMap[instance.Properties[i].PProperty.Name] = instance.Properties[i] + } + for i := 0; i < len(instance.Twins); i++ { + if v, ok := propertiesMap[instance.Twins[i].PropertyName]; ok { + instance.Twins[i].Property = &v + } + } + klog.V(2).Infof("final instance data from grpc = %v", instance) + return instance, nil +} diff --git a/mappers/usbcamera-dmi/pkg/util/parse/parse.go b/mappers/usbcamera-dmi/pkg/util/parse/parse.go new file mode 100755 index 00000000..5d22393f --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/util/parse/parse.go @@ -0,0 +1,68 @@ +/* +Copyright 2023 The KubeEdge Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parse + +import ( + "errors" + + "k8s.io/klog/v2" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/config" + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/util/grpcclient" +) + +var ErrEmptyData error = errors.New("device or device model list is empty") + +func ParseByUsingRegister(cfg *config.Config, + devices map[string]*common.DeviceInstance, + dms map[string]common.DeviceModel, + protocols map[string]common.ProtocolConfig) error { + deviceList, deviceModelList, err := grpcclient.RegisterMapper(cfg, true) + if err != nil { + return err + } + + if len(deviceList) == 0 || len(deviceModelList) == 0 { + return ErrEmptyData + } + modelMap := make(map[string]common.DeviceModel) + for _, model := range deviceModelList { + cur := ParseDeviceModelFromGrpc(model) + modelMap[model.Name] = cur + } + + for _, device := range deviceList { + commonModel := modelMap[device.Spec.DeviceModelReference] + protocol, err := BuildProtocolFromGrpc(device) + if err != nil { + return err + } + instance, err := ParseDeviceFromGrpc(device, &commonModel) + if err != nil { + return err + } + instance.PProtocol = protocol + devices[instance.ID] = new(common.DeviceInstance) + devices[instance.ID] = instance + klog.V(4).Info("Instance: ", instance.ID) + dms[instance.Model] = modelMap[instance.Model] + protocols[instance.ProtocolName] = protocol + } + + return nil +} diff --git a/mappers/usbcamera-dmi/pkg/util/parse/type.go b/mappers/usbcamera-dmi/pkg/util/parse/type.go new file mode 100755 index 00000000..854a9129 --- /dev/null +++ b/mappers/usbcamera-dmi/pkg/util/parse/type.go @@ -0,0 +1,99 @@ +package parse + +import ( + "fmt" + + "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/common" + dmiapi "github.com/kubeedge/mappers-go/mappers/usbcamera-dmi/pkg/dmi-api" +) + +func ConvTwinsToGrpc(twins []common.Twin) ([]*dmiapi.Twin, error) { + res := make([]*dmiapi.Twin, 0, len(twins)) + for _, twin := range twins { + cur := &dmiapi.Twin{ + PropertyName: twin.PropertyName, + ObservedDesired: &dmiapi.TwinProperty{ + Value: twin.ObservedDesired.Value, + Metadata: map[string]string{ + "type": twin.ObservedDesired.Metadata.Type, + "timestamp": twin.ObservedDesired.Metadata.Timestamp, + }, + }, + Reported: &dmiapi.TwinProperty{ + Value: twin.Reported.Value, + Metadata: map[string]string{ + "type": twin.Reported.Metadata.Type, + "timestamp": twin.Reported.Metadata.Timestamp, + }, + }, + } + res = append(res, cur) + } + return res, nil +} + +func ConvGrpcToTwins(twins []*dmiapi.Twin, srcTwins []common.Twin) ([]common.Twin, error) { + res := make([]common.Twin, 0, len(twins)) + for _, twin := range twins { + var srcTwin common.Twin + for _, found := range srcTwins { + if twin.GetPropertyName() == found.PropertyName { + srcTwin = found + break + } + } + if srcTwin.PropertyName == "" { + return nil, fmt.Errorf("not found src twin name %s while update status", twin.GetPropertyName()) + } + desiredMeta := twin.ObservedDesired.GetMetadata() + reportedMeta := twin.Reported.GetMetadata() + cur := common.Twin{ + PropertyName: twin.GetPropertyName(), + Property: srcTwin.Property, + ObservedDesired: common.TwinProperty{ + Value: twin.ObservedDesired.GetValue(), + }, + Reported: common.TwinProperty{ + Value: twin.Reported.GetValue(), + }, + } + if desiredMeta != nil { + cur.ObservedDesired.Metadata = common.Metadata{ + Timestamp: twin.ObservedDesired.GetMetadata()["timestamp"], + Type: twin.ObservedDesired.GetMetadata()["type"], + } + } + if reportedMeta != nil { + cur.Reported.Metadata = common.Metadata{ + Timestamp: twin.Reported.GetMetadata()["timestamp"], + Type: twin.Reported.GetMetadata()["type"], + } + } + res = append(res, cur) + } + return res, nil +} + +func ConvMsgTwinToGrpc(msgTwin map[string]*common.MsgTwin) []*dmiapi.Twin { + var twins []*dmiapi.Twin + for name, twin := range msgTwin { + twinData := &dmiapi.Twin{ + PropertyName: name, + Reported: &dmiapi.TwinProperty{ + Value: *twin.Actual.Value, + Metadata: map[string]string{ + "type": twin.Metadata.Type, + "timestamp": twin.Actual.Metadata.Timestamp, + }}, + ObservedDesired: &dmiapi.TwinProperty{ + Value: *twin.Expected.Value, + Metadata: map[string]string{ + "type": twin.Metadata.Type, + "timestamp": twin.Actual.Metadata.Timestamp, + }}, + } + twins = append(twins, twinData) + } + + return twins +} diff --git a/mappers/usbcamera-dmi/usbmapper-chart/.helmignore b/mappers/usbcamera-dmi/usbmapper-chart/.helmignore new file mode 100755 index 00000000..0e8a0eb3 --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/mappers/usbcamera-dmi/usbmapper-chart/Chart.yaml b/mappers/usbcamera-dmi/usbmapper-chart/Chart.yaml new file mode 100755 index 00000000..44f33f5d --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/Chart.yaml @@ -0,0 +1,29 @@ +apiVersion: v2 +name: usbmapper-chart +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.16.0" + + +dependencies: + - name: mapper + version: 0.1.0 \ No newline at end of file diff --git a/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/.helmignore b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/.helmignore new file mode 100755 index 00000000..0e8a0eb3 --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/Chart.yaml b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/Chart.yaml new file mode 100755 index 00000000..65ec0295 --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/Chart.yaml @@ -0,0 +1,28 @@ +apiVersion: v2 +name: mapper +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" + +dependencies: + - name: device-model + version: 0.1.0 \ No newline at end of file diff --git a/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/.helmignore b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/.helmignore new file mode 100755 index 00000000..0e8a0eb3 --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/Chart.yaml b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/Chart.yaml new file mode 100755 index 00000000..bde8640c --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: device-model +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/templates/000-pre-install-hook.yaml b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/templates/000-pre-install-hook.yaml new file mode 100755 index 00000000..7e811baa --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/templates/000-pre-install-hook.yaml @@ -0,0 +1,80 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: usb-camera-viewer + annotations: + "helm.sh/hook": pre-install, pre-upgrade + "helm.sh/hook-weight": "-6" + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list","patch"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: usb-camera-viewer-sa + namespace: default + annotations: + "helm.sh/hook": pre-install, pre-upgrade + "helm.sh/hook-weight": "-6" + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: usb-camera-viewer-binding + annotations: + "helm.sh/hook": pre-install, pre-upgrade + "helm.sh/hook-weight": "-6" + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed +subjects: + - kind: ServiceAccount + name: usb-camera-viewer-sa + namespace: default +roleRef: + kind: ClusterRole + name: usb-camera-viewer + apiGroup: rbac.authorization.k8s.io +--- +# templates/pre-install-job.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: pre-install-job + annotations: + "helm.sh/hook": pre-install, pre-upgrade + "helm.sh/hook-weight": "-5" + "helm.sh/hook-delete-policy": hook-succeeded,hook-failed + + + + +spec: + template: + spec: + serviceAccountName: usb-camera-viewer-sa + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node-role.kubernetes.io/agent + operator: DoesNotExist + hostPID: true + containers: + - name: pre-install-container + image: bitnami/kubectl + imagePullPolicy: IfNotPresent + command: + - /bin/sh + - -c + - | + {{- range $.Values.global.nodeSelectorAndDevPath.mapper }} + kubectl label nodes {{ .edgeNode }} edgeNode={{.edgeNode}} --overwrite + {{ end }} + securityContext: + privileged: true # 设置容器为特权容器,以便执行 hostPID 操作 + restartPolicy: OnFailure diff --git a/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/templates/001-camera-usb-device-model.yaml b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/templates/001-camera-usb-device-model.yaml new file mode 100755 index 00000000..eff8f546 --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/templates/001-camera-usb-device-model.yaml @@ -0,0 +1,83 @@ +apiVersion: devices.kubeedge.io/v1beta1 +kind: DeviceModel +metadata: + name: {{ $.Values.global.deviceModel.name }} + namespace: {{ $.Values.global.deviceModel.namespace }} +spec: + protocol: {{ $.Values.global.deviceModel.protocol }} + properties: + - name: Framerate + description: Framerate + type: FLOAT + accessMode: ReadWrite + - name: Input + description: Input + type: INT + accessMode: ReadOnly + - name: BusInfo + description: BusInfo + type: STRING + accessMode: ReadOnly + - name: WhiteBalanceTemperature + description: White Balance Temperature + type: INT + accessMode: ReadOnly + maximum: "6500" + minimum: "2800" + - name: WhiteBalanceTemperatureAuto + description: White Balance Temperature, Auto + type: INT + accessMode: ReadWrite + maximum: "1" + minimum: "0" + - name: ExposureAbsolute + description: Exposure (Absolute) + type: INT + accessMode: ReadOnly + maximum: "2500" + minimum: "5" + - name: ExposureAuto + description: Exposure, Auto + type: INT + accessMode: ReadWrite + maximum: "3" + minimum: "0" + - name: PowerLineFrequency + description: Power Line Frequency + type: INT + accessMode: ReadWrite + maximum: "2" + minimum: "0" + - name: Sharpness + description: Sharpness + type: INT + accessMode: ReadWrite + maximum: "255" + minimum: "1" + - name: Contrast + description: Contrast + type: INT + accessMode: ReadWrite + maximum: "255" + minimum: "1" + - name: Saturation + description: Saturation + type: INT + accessMode: ReadWrite + maximum: "255" + minimum: "1" + - name: Gain + description: Gain + type: INT + accessMode: ReadWrite + maximum: "100" + minimum: "1" + - name: Brightness + description: Brightness + type: INT + accessMode: ReadWrite + maximum: "255" + minimum: "1" + - name: ImageTrigger + type: STRING + accessMode: ReadOnly \ No newline at end of file diff --git a/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/values.yaml b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/charts/device-model/values.yaml new file mode 100755 index 00000000..e69de29b diff --git a/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/templates/002-mapper-deployment.yaml b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/templates/002-mapper-deployment.yaml new file mode 100755 index 00000000..a433ab99 --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/templates/002-mapper-deployment.yaml @@ -0,0 +1,97 @@ +{{- if $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.flag }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: influxdb-configmap +data: + token: "{{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.token }}" +{{- end }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: usb-dmi-mapper +spec: + replicas: {{ $.Values.global.replicaCounts.cameraUsbMapper.replicaCount }} + selector: + matchLabels: + app: cameraUsbMapper + template: + metadata: + labels: + app: cameraUsbMapper + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node-role.kubernetes.io/agent + operator: Exists + {{- if gt (len .Values.global.nodeSelectorAndDevPath.mapper) 0 }} + - key: edgeNode + operator: In + values: + {{- range .Values.global.nodeSelectorAndDevPath.mapper }} + - {{ .edgeNode | quote }} + {{- end }} + {{- end}} + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - cameraUsbMapper + topologyKey: "kubernetes.io/hostname" + containers: + - name: {{ .Values.global.images.cameraUsbMapper.name }} + image: {{ .Values.global.images.cameraUsbMapper.repository }}:{{ .Values.global.images.cameraUsbMapper.tag }} + imagePullPolicy: {{ .Values.global.images.cameraUsbMapper.pullPolicy }} + command: ["/bin/sh", "-c"] + args: ["/kubeedge/main --config-file /kubeedge/config.yaml --v 5"] + securityContext: + privileged: true + volumeMounts: + - mountPath: /dev + name: usb-dev + - name: sock-path + mountPath: /etc/kubeedge + {{- if $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.flag }} + env: + - name: TOKEN + valueFrom: + configMapKeyRef: + key: token + name: influxdb-configmap + {{- end }} + volumes: + - name: sock-path + hostPath: + path: /etc/kubeedge + type: Directory + - name: usb-dev + hostPath: + path: /dev + type: Directory + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.global.services.cameraUsbMapper.clusterIP.serviceName }} + namespace: {{ .Values.global.replicaCounts.cameraUsbMapper.namespace }} + labels: + service.kubernetes.io/service-proxy-name: "" #不让kube-proxy代理,交由edgeMesh代理 +spec: + ports: + - port: {{ .Values.global.services.cameraUsbMapper.clusterIP.port }} + targetPort: 8898 + protocol: TCP + selector: + app: cameraUsbMapper + type: ClusterIP + + + diff --git a/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/values.yaml b/mappers/usbcamera-dmi/usbmapper-chart/charts/mapper/values.yaml new file mode 100755 index 00000000..e69de29b diff --git a/mappers/usbcamera-dmi/usbmapper-chart/templates/003-influxdb-volume.yaml b/mappers/usbcamera-dmi/usbmapper-chart/templates/003-influxdb-volume.yaml new file mode 100755 index 00000000..a72d7a9d --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/templates/003-influxdb-volume.yaml @@ -0,0 +1,54 @@ +{{- if $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.flag }} +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: {{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.storage }} +provisioner: kubernetes.io/no-provisioner +#volumeBindingMode: WaitForFirstConsumer + + +{{- $replica:=int $.Values.global.replicaCounts.influxdb.replicaCount }} +{{- range $i := until $replica }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: influxdb-data-influxdb-{{ $i }} + namespace: {{ $.Values.global.replicaCounts.influxdb.namespace }} +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.storageSize }} + selector: + matchLabels: + app: influxdb-pv-{{ $i }} + storageClassName: {{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.storage }} + volumeMode: Filesystem +{{- end }} + + + +{{- range $i := until $replica }} +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: influxdb-pv-{{ $i }} + labels: + app: influxdb-pv-{{ $i }} +spec: + capacity: + storage: {{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.storageSize }} + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Delete + hostPath: + path: /var/lib/influxdb/data-{{ $i }} + type: DirectoryOrCreate + storageClassName: {{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.storage }} +{{- end }} +{{- end }} + diff --git a/mappers/usbcamera-dmi/usbmapper-chart/templates/004-influxdb-statefulset.yaml b/mappers/usbcamera-dmi/usbmapper-chart/templates/004-influxdb-statefulset.yaml new file mode 100755 index 00000000..610d0475 --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/templates/004-influxdb-statefulset.yaml @@ -0,0 +1,97 @@ +{{- if $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.flag }} +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + labels: + app: influxdb + name: influxdb + namespace: {{ .Values.global.replicaCounts.influxdb.namespace }} +spec: + serviceName: {{ .Values.global.services.influxdb.headless.serviceName }} + replicas: {{ .Values.global.replicaCounts.influxdb.replicaCount }} + selector: + matchLabels: + app: influxdb + template: + metadata: + labels: + app: influxdb + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node-role.kubernetes.io/agent + operator: Exists + containers: + - image: {{ .Values.global.images.influxdb.repository }}:{{ .Values.global.images.influxdb.tag }} + name: {{ .Values.global.images.influxdb.name }} + imagePullPolicy: {{ .Values.global.images.influxdb.pullPolicy }} + ports: + - containerPort: 8086 + name: influxdb + volumeMounts: + - mountPath: /var/lib/influxdb2 + name: influxdb-data + volumeClaimTemplates: + - metadata: + name: influxdb-data + namespace: {{ .Values.global.replicaCounts.influxdb.namespace }} + spec: + storageClassName: {{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.storage }} + accessModes: + - ReadWriteOnce +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.global.services.influxdb.nodePort.serviceName }} + namespace: {{ .Values.global.replicaCounts.influxdb.namespace }} + labels: + service.kubernetes.io/service-proxy-name: "" #不让kube-proxy代理,交由edgeMesh代理 +spec: + ports: + - name: {{ .Values.global.services.influxdb.nodePort.serviceName }} + port: 8086 + targetPort: 8086 + nodePort: {{ .Values.global.services.influxdb.nodePort.port }} + selector: + app: influxdb + type: NodePort +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.global.services.influxdb.clusterIP.serviceName }} + namespace: {{ .Values.global.replicaCounts.influxdb.namespace }} + labels: + service.kubernetes.io/service-proxy-name: "" #不让kube-proxy代理,交由edgeMesh代理 +spec: + ports: + - port: {{ .Values.global.services.influxdb.clusterIP.port }} + targetPort: 8086 + protocol: TCP + name: {{ .Values.global.services.influxdb.clusterIP.serviceName }} + selector: + app: influxdb + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.global.services.influxdb.headless.serviceName }} + namespace: {{ .Values.global.replicaCounts.influxdb.namespace }} + labels: + service.kubernetes.io/service-proxy-name: "" #不让kube-proxy代理,交由edgeMesh代理 +spec: + ports: + - port: {{ .Values.global.services.influxdb.headless.port }} + targetPort: 8086 + protocol: TCP + name: {{ .Values.global.services.influxdb.headless.serviceName }} + clusterIP: None + selector: + app: influxdb +{{- end }} \ No newline at end of file diff --git a/mappers/usbcamera-dmi/usbmapper-chart/templates/005-redis-volume.yaml b/mappers/usbcamera-dmi/usbmapper-chart/templates/005-redis-volume.yaml new file mode 100755 index 00000000..8d317c39 --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/templates/005-redis-volume.yaml @@ -0,0 +1,51 @@ +{{- if $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.redis.flag }} +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: {{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.redis.flag }} +provisioner: kubernetes.io/no-provisioner +#volumeBindingMode: WaitForFirstConsumer + +{{- $replica:=int $.Values.global.replicaCounts.redis.replicaCount }} +{{- range $i := until $replica }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: redis-data-redis-{{ $i }} + namespace: {{ $.Values.global.replicaCounts.redis.namespace }} +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.redis.storageSize }} + selector: + matchLabels: + app: redis-pv-{{ $i }} + storageClassName: {{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.redis.storage }} + volumeMode: Filesystem +{{- end }} + +{{- range $i := until $replica }} +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: redis-pv-{{ $i }} + labels: + app: redis-pv-{{ $i }} +spec: + capacity: + storage: {{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.redis.storageSize }} + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Delete + hostPath: + path: /var/lib/redis/data-{{ $i }} + type: DirectoryOrCreate + storageClassName: {{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.redis.storage }} +{{- end }} + +{{- end }} \ No newline at end of file diff --git a/mappers/usbcamera-dmi/usbmapper-chart/templates/006-redis-statefulset.yaml b/mappers/usbcamera-dmi/usbmapper-chart/templates/006-redis-statefulset.yaml new file mode 100755 index 00000000..c40572b7 --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/templates/006-redis-statefulset.yaml @@ -0,0 +1,129 @@ +{{- if $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.redis.flag }} +--- +apiVersion: v1 +data: + redis.conf: |- + bind 0.0.0.0 + port 6379 + #requirepass "" + pidfile /var/run/redis_6379.pid + save 900 1 + save 300 10 + save 60 10000 + rdbcompression yes + rdbchecksum yes + dbfilename dump.rdb + appendonly yes + appendfilename "appendonly.aof" + appendfsync everysec + dir /data + logfile "/data/redis-6379.log" + protected-mode no +kind: ConfigMap +metadata: + name: redis-config + namespace: {{ .Values.global.replicaCounts.redis.namespace }} +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: redis + namespace: {{ .Values.global.replicaCounts.redis.namespace }} +spec: + replicas: {{ .Values.global.replicaCounts.redis.replicaCount }} + selector: + matchLabels: + app: redis + serviceName: {{ $.Values.global.services.redis.headless.serviceName }} + template: + metadata: + labels: + app: redis + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node-role.kubernetes.io/agent + operator: DoesNotExist + containers: + - image: {{ .Values.global.images.redis.repository }}:{{ .Values.global.images.redis.tag }} + command: [ "redis-server","/etc/redis/redis.conf" ] + name: {{ .Values.global.images.redis.name }} + volumeMounts: + - name: redis-config + mountPath: /etc/redis/redis.conf + subPath: redis.conf + - name: redis-data + mountPath: /data + volumes: + - name: redis-config + configMap: + name: redis-config + - name: redis-data + persistentVolumeClaim: + claimName: redis-data-redis + volumeClaimTemplates: + - metadata: + name: redis-data + namespace: {{ .Values.global.replicaCounts.redis.namespace }} + spec: + storageClassName: {{ $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.redis.storage }} + accessModes: + - ReadWriteOnce + +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.global.services.redis.nodePort.serviceName }} + namespace: {{ .Values.global.replicaCounts.redis.namespace }} + labels: + service.kubernetes.io/service-proxy-name: "" #不让kube-proxy代理,交由edgeMesh代理 +spec: + type: NodePort # 如果需要集群外部访问,这里改为NodePort + ports: + - port: 6379 + protocol: TCP + targetPort: 6379 + name: {{ .Values.global.services.redis.nodePort.serviceName }} + nodePort: {{ .Values.global.services.redis.nodePort.port }} + selector: + app: redis +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.global.services.redis.clusterIP.serviceName }} + namespace: {{ .Values.global.replicaCounts.redis.namespace }} + labels: + service.kubernetes.io/service-proxy-name: "" #不让kube-proxy代理,交由edgeMesh代理 +spec: + type: ClusterIP # 如果需要集群外部访问,这里改为NodePort + ports: + - port: {{ .Values.global.services.redis.clusterIP.port }} + protocol: TCP + targetPort: 6379 + name: {{ $.Values.global.services.redis.clusterIP.serviceName }} + selector: + app: redis +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ $.Values.global.services.redis.headless.serviceName }} + namespace: {{ $.Values.global.replicaCounts.redis.namespace }} + labels: + service.kubernetes.io/service-proxy-name: "" #不让kube-proxy代理,交由edgeMesh代理 +spec: + clusterIP: None + ports: + - port: {{ $.Values.global.services.redis.headless.port }} + protocol: TCP + targetPort: 6379 + name: {{ $.Values.global.services.redis.headless.serviceName }} + selector: + app: redis + +{{- end}} diff --git a/mappers/usbcamera-dmi/usbmapper-chart/templates/007-camera-usb-device-instance.yaml b/mappers/usbcamera-dmi/usbmapper-chart/templates/007-camera-usb-device-instance.yaml new file mode 100755 index 00000000..63f6dece --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/templates/007-camera-usb-device-instance.yaml @@ -0,0 +1,213 @@ +{{- $replicaCount := int .Values.global.replicaCounts.cameraUsbMapper.replicaCount }} +{{- $mappers := .Values.global.nodeSelectorAndDevPath.mapper }} +{{- range $i := until $replicaCount }} +--- +apiVersion: devices.kubeedge.io/v1beta1 +kind: Device +metadata: + name: camera-usb-{{ $i }} + labels: + model: {{ $.Values.global.deviceModel.name }} +spec: + deviceModelRef: + name: {{ $.Values.global.deviceModel.name }} + protocol: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + deviceID: {{ $i }} + width: 640 + height: 480 + format: 0x56595559 + serialPort: {{ index $mappers $i "devPath" }} + protocolID: {{ $i }} + nodeName: {{ index $mappers $i "edgeNode" }} #pls give your edge node name + properties: + - name: Framerate + desired: + value: "30" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "Framerate" + dataType: float + reportToCloud: true + - name: Input + desired: + value: "0" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "Input" + dataType: int + reportToCloud: true + - name: BusInfo + desired: + value: "usb-0000:02:02.0-1" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "BusInfo" + dataType: string + reportToCloud: true + - name: WhiteBalanceTemperatureAuto + desired: + value: "1" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "White Balance Temperature, Auto" + dataType: int + reportToCloud: true + - name: WhiteBalanceTemperature + desired: + value: "4650" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "White Balance Temperature" + dataType: int + reportToCloud: true + - name: ExposureAbsolute + desired: + value: "5" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "Exposure (Absolute)" + dataType: int + reportToCloud: true + - name: ExposureAuto + desired: + value: "0" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "Exposure, Auto" + dataType: int + reportToCloud: true + - name: PowerLineFrequency + desired: + value: "1" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "Power Line Frequency" + dataType: int + reportToCloud: true + - name: Sharpness + desired: + value: "128" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "Sharpness" + dataType: int + reportToCloud: true + - name: Contrast + desired: + value: "128" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "Contrast" + dataType: int + reportToCloud: true + - name: Saturation + desired: + value: "128" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "Saturation" + dataType: int + reportToCloud: true + - name: Gain + desired: + value: "50" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "Gain" + dataType: int + reportToCloud: true + - name: Brightness + desired: + value: "128" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "Brightness" + dataType: int + reportToCloud: true + - name: ImageTrigger + desired: + value: "" + metadata: + timestamp: '1550049403598' + visitors: + protocolName: {{ $.Values.global.deviceModel.protocol }} + configData: + featureName: "ImageTrigger" + dataType: string + reportToCloud: false + {{- if $.Values.global.nodeSelectorAndDevPath.pushMethod.fag }} + pushMethod: + {{- if $.Values.global.nodeSelectorAndDevPath.pushMethod.mqtt.flag }} + mqtt: + topic: "camera-usb-{{ $i }}" + {{- with $.Values.global.nodeSelectorAndDevPath.pushMethod.mqtt.conf }} + {{- toYaml . | nindent 10 }} + {{- end }} + {{- end}} + {{- if $.Values.global.nodeSelectorAndDevPath.pushMethod.http.flag }} + http: + {{- with $.Values.global.nodeSelectorAndDevPath.pushMethod.http.conf }} + {{- toYaml . | nindent 10}} + {{- end}} + {{- end}} + {{- if $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.flag }} + dbMethod: + {{- if $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.flag }} + influxdb2: + influxdb2ClientConfig: + bucket: "camera-usb-{{ $i }}" + url: http://{{ $.Values.global.services.influxdb.clusterIP.serviceName }}.{{ $.Values.global.replicaCounts.influxdb.namespace }}.svc.cluster.local:{{ $.Values.global.services.influxdb.clusterIP.port }} + {{- with $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.conf.influxdb2ClientConfig }} + {{- toYaml . | nindent 14 }} + {{- end }} + influxdb2DataConfig: + tag: + usb-camera-id: camera-usb-{{ $i }} + {{- with $.Values.global.nodeSelectorAndDevPath.pushMethod.dbMethod.influxdb2.conf.influxdb2DataConfig }} + {{- toYaml . | nindent 14 }} + {{- end }} + {{- end }} + {{- end}} + {{- end}} +{{- end }} \ No newline at end of file diff --git a/mappers/usbcamera-dmi/usbmapper-chart/templates/_helpers.tpl b/mappers/usbcamera-dmi/usbmapper-chart/templates/_helpers.tpl new file mode 100755 index 00000000..c602f00f --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/templates/_helpers.tpl @@ -0,0 +1,65 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "usbmapper-chart.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "usbmapper-chart.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "usbmapper-chart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "usbmapper-chart.labels" -}} +helm.sh/chart: {{ include "usbmapper-chart.chart" . }} +{{ include "usbmapper-chart.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "usbmapper-chart.selectorLabels" -}} +app.kubernetes.io/name: {{ include "usbmapper-chart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "usbmapper-chart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "usbmapper-chart.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + + + diff --git a/mappers/usbcamera-dmi/usbmapper-chart/values.yaml b/mappers/usbcamera-dmi/usbmapper-chart/values.yaml new file mode 100755 index 00000000..64e9b2ba --- /dev/null +++ b/mappers/usbcamera-dmi/usbmapper-chart/values.yaml @@ -0,0 +1,125 @@ +global: + replicaCounts: + influxdb: + replicaCount: 1 + namespace: default + redis: + namespace: default + replicaCount: 2 + cameraUsbMapper: + replicaCount: 1 + namespace: default + deviceModel: + namespace: default + name: camera-usb + protocol: camera-usb + waitTimes: 500000 + + nodeSelectorAndDevPath: + pushMethod: + fag: true + mqtt: + flag: false + conf: + address: 'http://127.0.0.1:1883' + retained: true + http: + flag: false + conf: + hostName: '' + port: 0 + requestPath: '/' + timeout: 0 + dbMethod: + flag: true + influxdb2: + flag: true + storageSize: 10Gi + storage: "influxdb-storage" + token: "aDSvXfxdjUmVF66qbt-y2-U146cxRdiw_AKUgQNPfWszSrmFQAtyl7IA0pVqua_VuS4_JBZbi3mNCsL3wUA2Ig==" + conf: + influxdb2ClientConfig: + org: 'kubeEdge' + influxdb2DataConfig: + measurement: "usb-camera" + fieldKey: "image-value" + redis: + flag: false + storage: "redis-storage" + storageSize: 10Gi + mapper: +# - edgeNode: "edgenode02" +# devPath: '/dev/video0' + - edgeNode: "edgenode1" + devPath: '/dev/video17' + + + images: + influxdb: + repository: influxdb + tag: 2.1.1 + name: influxdb + pullPolicy: IfNotPresent + redis: + repository: redis + tag: 5.0.5 + name: redis + pullPolicy: IfNotPresent + cameraUsbMapper: + repository: camerausbmapper + tag: v2.0 + name: camerausbmapper + pullPolicy: IfNotPresent + + imagePullSecrets: [ ] + nameOverride: "" + fullnameOverride: "" + + serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: { } + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + + podAnnotations: { } + podSecurityContext: { } + + securityContext: { } + + services: + redis: + clusterIP: + port: 6379 + serviceName: redis-cluster-ip + nodePort: + port: 32379 + serviceName: redis + headless: + port: 6379 + serviceName: redis-service + influxdb: + clusterIP: + port: 8086 + serviceName: influxdb-cluster-ip + nodePort: + port: 32086 + serviceName: influxdb + headless: + port: 8086 + serviceName: influxdb-service + cameraUsbMapper: + clusterIP: + port: 8898 + serviceName: camerausbmapper-cluster-ip + nodePort: + port: 32898 + serviceName: camerausbmapper + headless: + port: 8898 + serviceName: camerausbmapper-service + + + diff --git a/pkg/global/global.go b/pkg/global/global.go index f6fbfced..eb89ad74 100644 --- a/pkg/global/global.go +++ b/pkg/global/global.go @@ -5,15 +5,28 @@ import ( "github.com/kubeedge/mappers-go/pkg/common" ) +// DevPanel defined operations on devices, manage the lifecycle of devices type DevPanel interface { + // DevStart start device to collect/push/save data to edgecore/app/database DevStart() + // DevInit get device info by dmi interface DevInit(cfg *config.Config) error + // UpdateDev update device's config and restart the device UpdateDev(model *common.DeviceModel, device *common.DeviceInstance, protocol *common.Protocol) + // UpdateDevTwins update device twin's config and restart the device UpdateDevTwins(deviceID string, twins []common.Twin) error + // DealDeviceTwinGet get device's twin data DealDeviceTwinGet(deviceID string, twinName string) (interface{}, error) + // GetDevice get device's instance info GetDevice(deviceID string) (interface{}, error) + // RemoveDevice stop device and remove device RemoveDevice(deviceID string) error + // GetModel get model's info GetModel(modelName string) (common.DeviceModel, error) + // UpdateModel update model in map only UpdateModel(model *common.DeviceModel) + // RemoveModel remove model in map only RemoveModel(modelName string) + // GetTwinResult get device's property value and datatype + GetTwinResult(deviceID string, twinName string) (string, string, error) }