Skip to content

Commit

Permalink
feat: add bluetooth adaptor
Browse files Browse the repository at this point in the history
add bluetooth adaptor logic

Co-authored-by: Guangbo Chen <steven.guangbo.chen@gmail.com>
Signed-off-by: Guangbo Chen <steven.guangbo.chen@gmail.com>
  • Loading branch information
Frank Mai and guangbochen committed Apr 13, 2020
1 parent c2ed83b commit 9b81d89
Show file tree
Hide file tree
Showing 28 changed files with 2,044 additions and 0 deletions.
12 changes: 12 additions & 0 deletions adaptors/ble/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM --platform=$TARGETPLATFORM scratch

# automatic platform ARGs, ref to:
# - https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
ARG TARGETPLATFORM
ARG TARGETOS
ARG TARGETARCH

WORKDIR /
VOLUME /var/lib/octopus/adaptors
COPY bin/ble_${TARGETOS}_${TARGETARCH} /ble
ENTRYPOINT ["/ble"]
36 changes: 36 additions & 0 deletions adaptors/ble/Dockerfile.dapper
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
FROM golang:1.13.9-buster
RUN apt-get update && \
apt-get install -y xz-utils unzip

# -- for make rules
## install docker
RUN curl -sSfL "https://get.docker.com" | sh -s VERSION=19.03; \
docker --version
## install kubectl
RUN curl -fL "https://storage.googleapis.com/kubernetes-release/release/v1.17.2/bin/$(go env GOOS)/$(go env GOARCH)/kubectl" -o /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl; \
kubectl version --short --client
## install golangci-lint
RUN if [ "$(go env GOARCH)" = "amd64" ]; then \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "$(go env GOPATH)/bin" v1.24.0; \
golangci-lint --version; \
fi
## install controller-gen
RUN if [ "$(go env GOARCH)" = "amd64" ]; then \
GO111MODULE=on go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.5; \
controller-gen --version; \
fi
# -- for make rules

# -- for dapper
ENV DAPPER_RUN_ARGS --privileged --network host
ENV GO111MODULE=off
ENV CROSS=false
ENV DAPPER_ENV CROSS LOCAL_CLUSTER_KIND DOCKER_USERNAME DOCKER_PASSWORD WITHOUT_MANIFEST ONLY_MANIFEST IGNORE_MISSING DRONE_TAG REPO TAG OS ARCH IMAGE_NAME
ENV DAPPER_SOURCE /go/src/github.com/rancher/octopus/
ENV DAPPER_OUTPUT ./adaptors/ble/bin ./adaptors/ble/dist ./adaptors/ble/deploy ./adaptors/ble/api
ENV DAPPER_DOCKER_SOCKET true
ENV HOME ${DAPPER_SOURCE}
# -- for dapper

WORKDIR ${DAPPER_SOURCE}
ENTRYPOINT ["make", "-se", "adaptor"]
49 changes: 49 additions & 0 deletions adaptors/ble/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
SHELL := /bin/bash

# Borrowed from https://stackoverflow.com/questions/18136918/how-to-get-current-relative-directory-of-your-makefile
curr_dir := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))

# Borrowed from https://stackoverflow.com/questions/2214575/passing-arguments-to-make-run
rest_args := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(rest_args):;@:)

all: help

help:
# Building process.
#
# Usage:
# make adaptor {adaptor-name} <stage> [only]
#
# Stage:
# a "stage" consists of serval actions, actions follow as below:
# generate -> mod -> lint -> build -> containerize -> deploy
# \ -> test -> verify -> e2e
# for convenience, the name of the "action" also represents the current "stage".
# choosing to execute a certain "stage" will execute all actions in the previous sequence.
#
# Actions:
# - generate, g : generate deployment manifests and code implementations via `controller-gen`.
# - mod, m : download code dependencies.
# - lint, l : verify code via `golangci-lint`,
# roll back to `go fmt` and `go vet` if the installation fails.
# - build, b : compile code.
# - package, p : package docker image.
# - deploy, d : push docker image.
# - test, t : run unit tests.
# - verify, v : run integration tests.
# - e2e, e : run e2e tests.
# only executing the corresponding "action" of a "stage" needs the `only` suffix.
# integrate with dapper via `BY=dapper`.
#
# Example:
# - make adaptor ble : execute `build` stage for "ble" adaptor.
# - make adaptor ble test : execute `test` stage for "ble" adaptor.
# - make adaptor ble build only : only execute `build` action for "ble" adaptor, during `build` stage.
@echo

make_rules := $(shell ls $(curr_dir)/hack/make-rules | sed 's/.sh//g')
$(make_rules):
@$(curr_dir)/hack/make-rules/$@.sh $(rest_args)

.PHONY: $(make_rules) test deploy pkg
128 changes: 128 additions & 0 deletions adaptors/ble/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# BLE Adaptor

This is BLE(Bluetooth Low Energy) adaptor is used for bluetooth devices connection.

## Registration Information

| Versions | Register Name | Endpoint Socket | Available |
|:---:|:---:|:---:|:---:|
| `v1alpha1` | `adaptors.edge.cattle.io/ble` | `ble.socket` | * |

## Support Model

| Kind | Group | Version | Available |
|:---:|:---:|:---:|:---:|
| `BluetoothDevice` | `devices.edge.cattle.io` | `v1alpha1` | * |

## Support Platform

| OS | Arch |
|:---:|:---|
| `linux` | `amd64` |
| `linux` | `arm` |
| `linux` | `arm64` |

## Usage

```shell script
kubectl apply -f ./deploy/e2e/all_in_one.yaml
```

## Authority

Grant permissions to Octopus as below:

```text
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
bluetoothdevices.devices.edge.cattle.io [] [] [create delete get list patch update watch]
bluetoothdevices.devices.edge.cattle.io/status [] [] [get patch update]
```

## BLE Device Parameters

Parameter | Description | Scheme | Required
--- | --- | --- | ---
name | Device name | string | either device name or macAddress is required
macAddress | Device access mac address | string | either name or macAddress is required
properties | Device properties | []*[DeviceProperty](#deviceproperty) | false


### DeviceProperty

Parameter | Description | Scheme | Required
--- | --- | --- | ---
name | Property name | string | true
description | Property description | string | false
accessMode | Property accessMode | *[PropertyAccessMode](#propertyaccessmode) | true
visitor | Property visitor | *[PropertyVisitor](#propertyvisitor) | true

### PropertyAccessMode
Parameter | Description | Scheme | Required
--- | --- | --- | ---
ReadOnly | Property access mode is read only | string | false
ReadWrite | Property access mode is read and write | string | false
NotifyOnly | Property access mode is notify only | string | false

### PropertyVisitor
Parameter | Description | Scheme | Required
--- | --- | --- | ---
characteristicUUID | Property UUID | string | true
defaultValue | Config data write to the bluetooth device(set when access mode is `ReadWrite`), for example `ON` configed in the dataWrite | string | false
dataWrite | Responsible for converting the data from the string into []byte that is understood by the bluetooth device, for example: `"ON":[1], "OFF":[0]` | string | false
dataConverter | Responsible for converting the data being read from the bluetooth device into string | *[BluetoothDataConverter](#bluetoothdataconverter) | false

### BluetoothDataConverter
Parameter | Description | Scheme | Required
--- | --- | --- | ---
startIndex | Specifies the start index of the incoming byte stream to be converted | int | true
endIndex | Specifies the end index of incoming byte stream to be converted | int | true
shiftLeft | Specifies the number of bits to shift left | int | false
shiftRight | Specifies the number of bits to shift right | int | false
orderOfOperations | Specifies in what order the operations | []*[BluetoothOperations](#BluetoothOperations) | false

### BluetoothOperations
Parameter | Description | Scheme | Required
--- | --- | --- | ---
operationType | Specifies the operation to be performed | *[BluetoothArithmeticOperationType](#bluetootharithmeticoperationtype) | true
operationValue | Specifies with what value the operation is to be performed | string | true

### BluetoothArithmeticOperationType
Parameter | Description | Scheme | Required
--- | --- | --- | ---
Add | Arithmetic operation of add | string | false
Subtract | Arithmetic operation of subtract | string | false
Multiply | Arithmetic operation of multiply | string | false
Divide | Arithmetic operation of divide | string | false

## Example of BLE deviceLink YAML
```YAML
apiVersion: edge.cattle.io/v1alpha1
kind: DeviceLink
metadata:
name: xiaomi-temp-rs2200
spec:
adaptor:
node: ubuntu
name: adaptors.edge.cattle.io/ble
parameters:
syncInterval: 30
timeout: 60
model:
apiVersion: "devices.edge.cattle.io/v1alpha1"
kind: "BluetoothDevice"
template:
metadata:
labels:
device: xiaomi-temp-rs2200
spec:
name: "MJ_HT_V1"
# macAddress: ""
properties:
- name: data
description: XiaoMi temp sensor with temperature and humidity data
accessMode: NotifyOnly
visitor:
characteristicUUID: 226c000064764566756266734470666d
```
For more BLE deviceLink examples, please refer to the [deploy/e2e](./deploy/e2e/) directory.
102 changes: 102 additions & 0 deletions adaptors/ble/api/v1alpha1/bluetoothdevice_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// BluetoothDeviceSpec defines the desired state of BluetoothDevice
type BluetoothDeviceSpec struct {
Properties []DeviceProperty `json:"properties,omitempty"`
Name string `json:"name,omitempty"`
MacAddress string `json:"macAddress,omitempty"`
}

// DeviceProperty defines an individual ble device property
type DeviceProperty struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
AccessMode PropertyAccessMode `json:"accessMode,omitempty"`
Visitor PropertyVisitor `json:"visitor,omitempty"`
}

// The access mode for a device property.
type PropertyAccessMode string

// Access mode constants for a device property.
const (
ReadWrite PropertyAccessMode = "ReadWrite"
ReadOnly PropertyAccessMode = "ReadOnly"
NotifyOnly PropertyAccessMode = "NotifyOnly"
)

// PropertyVisitor defines the specifics of accessing a particular device property
type PropertyVisitor struct {
CharacteristicUUID string `json:"characteristicUUID,omitempty"`
DefaultValue string `json:"defaultValue,omitempty"`
DataWriteTo map[string][]byte `json:"dataWrite,omitempty"`
BluetoothDataConverter BluetoothDataConverter `json:"dataConverter,omitempty"`
}

// BluetoothDataConverter defines the read data converting operation
type BluetoothDataConverter struct {
StartIndex int `json:"startIndex,omitempty"`
EndIndex int `json:"endIndex,omitempty"`
ShiftLeft int `json:"shiftLeft,omitempty"`
ShiftRight int `json:"shiftRight,omitempty"`
OrderOfOperations []BluetoothOperations `json:"orderOfOperations,omitempty"`
}

type BluetoothOperations struct {
OperationType ArithOperationType `json:"operationType,omitempty"`
OperationValue string `json:"operationValue,omitempty"`
}

type ArithOperationType string

const (
OperationAdd ArithOperationType = "Add"
OperationSubtract ArithOperationType = "Subtract"
OperationMultiply ArithOperationType = "Multiply"
OperationDivide ArithOperationType = "Divide"
)

// BluetoothDeviceStatus defines the observed state of BluetoothDevice
type BluetoothDeviceStatus struct {
Properties []StatusProperties `json:"properties,omitempty"`
}

type StatusProperties struct {
Name string `json:"name,omitempty"`
Desired string `json:"desired,omitempty"`
Reported string `json:"reported,omitempty"`
UpdatedAt metav1.Time `json:"updatedAt,omitempty"`
}

// +kubebuilder:object:root=true
// +k8s:openapi-gen=true
// +kubebuilder:resource:shortName=ble
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Name",type=string,JSONPath=`.spec.name`
// +kubebuilder:printcolumn:name="MacAddress",type=integer,JSONPath=`.spec.macAddress`
// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
// BluetoothDevice is the Schema for the ble device API
type BluetoothDevice struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec BluetoothDeviceSpec `json:"spec,omitempty"`
Status BluetoothDeviceStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true
// +k8s:openapi-gen=true
// BluetoothDeviceList contains a list of BLE devices
type BluetoothDeviceList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []BluetoothDevice `json:"items"`
}

func init() {
SchemeBuilder.Register(&BluetoothDevice{}, &BluetoothDeviceList{})
}
35 changes: 35 additions & 0 deletions adaptors/ble/api/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
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 v1alpha1 contains API Schema definitions for the edge v1alpha1 API group
// +kubebuilder:object:generate=true
// +groupName=devices.edge.cattle.io
package v1alpha1

import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)

var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "devices.edge.cattle.io", Version: "v1alpha1"}

// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}

// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
Loading

0 comments on commit 9b81d89

Please sign in to comment.