├── .gitignore ├── examples ├── Blink │ ├── wiring.fzz │ ├── wiring.png │ ├── config_clients.png │ ├── config_service.png │ ├── nodered_import.png │ ├── nodered_clipboard.png │ ├── nodered_dashboard.png │ ├── configuration.toml │ ├── RPi_Blink_Led.yaml │ ├── README.md │ ├── blink_flow.json │ └── docker-compose.yml └── MotionDetector │ ├── wiring.fzz │ ├── wiring.png │ ├── config_clients.png │ ├── config_service.png │ ├── nodered_import.png │ ├── nodered_clipboard.png │ ├── nodered_commands.png │ ├── nodered_dashboard.png │ ├── register_mqtt_export.sh │ ├── configuration.toml │ ├── RPi_Motion_Detector.yaml │ ├── README.md │ ├── docker-compose.yml │ └── motion_detector_flow.json ├── snap ├── hooks │ └── install └── snapcraft.yaml ├── src └── c │ ├── cmake │ ├── FindLibMRAA.cmake │ └── FindLibcsdk.cmake │ ├── CMakeLists.txt │ ├── device_rpi.h │ └── main.c ├── scripts ├── build.sh ├── build_deps.sh ├── Dockerfile.alpine-3.8 └── rpi_patch ├── res └── configuration.toml ├── Build-Snap.md ├── Build-Docker.md ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /deps/ 3 | *.log 4 | *.snap -------------------------------------------------------------------------------- /examples/Blink/wiring.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/Blink/wiring.fzz -------------------------------------------------------------------------------- /examples/Blink/wiring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/Blink/wiring.png -------------------------------------------------------------------------------- /examples/Blink/config_clients.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/Blink/config_clients.png -------------------------------------------------------------------------------- /examples/Blink/config_service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/Blink/config_service.png -------------------------------------------------------------------------------- /examples/Blink/nodered_import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/Blink/nodered_import.png -------------------------------------------------------------------------------- /examples/Blink/nodered_clipboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/Blink/nodered_clipboard.png -------------------------------------------------------------------------------- /examples/Blink/nodered_dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/Blink/nodered_dashboard.png -------------------------------------------------------------------------------- /examples/MotionDetector/wiring.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/MotionDetector/wiring.fzz -------------------------------------------------------------------------------- /examples/MotionDetector/wiring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/MotionDetector/wiring.png -------------------------------------------------------------------------------- /snap/hooks/install: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # copy all the examples into $SNAP_DATA 4 | cp -r "$SNAP/examples" "$SNAP_DATA/examples" 5 | -------------------------------------------------------------------------------- /examples/MotionDetector/config_clients.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/MotionDetector/config_clients.png -------------------------------------------------------------------------------- /examples/MotionDetector/config_service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/MotionDetector/config_service.png -------------------------------------------------------------------------------- /examples/MotionDetector/nodered_import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/MotionDetector/nodered_import.png -------------------------------------------------------------------------------- /examples/MotionDetector/nodered_clipboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/MotionDetector/nodered_clipboard.png -------------------------------------------------------------------------------- /examples/MotionDetector/nodered_commands.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/MotionDetector/nodered_commands.png -------------------------------------------------------------------------------- /examples/MotionDetector/nodered_dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhall119/edgex-device-rpi/HEAD/examples/MotionDetector/nodered_dashboard.png -------------------------------------------------------------------------------- /src/c/cmake/FindLibMRAA.cmake: -------------------------------------------------------------------------------- 1 | find_path (LIBMRAA_INCLUDE_DIR mraa.h) 2 | find_library (LIBMRAA_LIBRARIES NAMES mraa libmraa) 3 | include (FindPackageHandleStandardArgs) 4 | find_package_handle_standard_args (LIBMRAA DEFAULT_MSG LIBMRAA_LIBRARIES LIBMRAA_INCLUDE_DIR) 5 | -------------------------------------------------------------------------------- /src/c/cmake/FindLibcsdk.cmake: -------------------------------------------------------------------------------- 1 | find_path (LIBCSDK_INCLUDE_DIR edgex/edgex.h edgex/devsdk.h) 2 | find_library (LIBCSDK_LIBRARIES NAMES csdk libcsdk) 3 | include (FindPackageHandleStandardArgs) 4 | find_package_handle_standard_args (LIBCSDK DEFAULT_MSG LIBCSDK_LIBRARIES LIBCSDK_INCLUDE_DIR) 5 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e -x 3 | 4 | # Find root directory and system type 5 | 6 | ROOT=$(dirname $(dirname $(readlink -f $0))) 7 | echo $ROOT 8 | cd $ROOT 9 | 10 | # Cmake release build 11 | 12 | mkdir -p $ROOT/build/release 13 | cd $ROOT/build/release 14 | cmake -DCMAKE_BUILD_TYPE=Release $ROOT/src/c 15 | make 2>&1 | tee release.log 16 | 17 | -------------------------------------------------------------------------------- /examples/MotionDetector/register_mqtt_export.sh: -------------------------------------------------------------------------------- 1 | #1/bin/sh 2 | 3 | curl -X POST -d '{ 4 | "name":"ExampleRPiMotionEvents", 5 | "addressable":{ 6 | "name":"EdgeXMQTTBroker", 7 | "protocol":"tcp", 8 | "address":"edgex_mqtt_broker", 9 | "port":1883, 10 | "publisher":"EdgeXExportPublisher", 11 | "topic":"ExampleRpiMotion" 12 | }, 13 | "format":"JSON", 14 | "filter":{ 15 | "deviceIdentifiers":["RPiMotionDetector"] 16 | }, 17 | "enable":true, 18 | "destination":"MQTT_TOPIC" 19 | }' http://localhost:48071/api/v1/registration 20 | -------------------------------------------------------------------------------- /res/configuration.toml: -------------------------------------------------------------------------------- 1 | [Service] 2 | Host = "edgex-device-rpi" 3 | Port = 49991 4 | ConnectRetries = 3 5 | HealthCheck = "" 6 | StartupMsg = "device RPI started" 7 | ReadMaxLimit = 256 8 | Timeout = 5000 9 | 10 | [Clients] 11 | [Clients.Data] 12 | Host = "edgex-core-data" 13 | Port = 48080 14 | 15 | [Clients.Metadata] 16 | Host = "edgex-core-metadata" 17 | Port = 48081 18 | 19 | [Device] 20 | DataTransform = true 21 | Discovery = false 22 | InitCmd = "" 23 | InitCmdArgs = "" 24 | MaxCmdOps = 128 25 | MaxCmdResultLen = 256 26 | RemoveCmd = "" 27 | RemoveCmdArgs = "" 28 | ProfilesDir = "" 29 | SendReadingsOnChanged = true 30 | 31 | [Logging] 32 | RemoteURL = "" 33 | File = "-" 34 | 35 | 36 | -------------------------------------------------------------------------------- /Build-Snap.md: -------------------------------------------------------------------------------- 1 | ## Build Snap package: 2 | 3 | 1. Check out edgex-device-rpi repo: 4 | ``` 5 | git clone https://github.com/mhall119/edgex-device-rpi 6 | ``` 7 | 8 | 2. Install the **Snapcraft** tool from the snap store: 9 | 10 | ``` 11 | snap install snapcraft 12 | ``` 13 | 14 | 3. Build a snap package by using the following command 15 | ``` 16 | cd edgex-device-rpi 17 | snapcraft snap 18 | ``` 19 | 20 | This command will build the edgex-device-rpi release image. 21 | By default, the configuration and profile file used by the service are available in `$SNAP_DATA/res` folder, but you can override 22 | that by passing in the `$SNAP_DATA/examples/` path you want to use. See the [Example Projects](#example-projects) below for more. 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/Blink/configuration.toml: -------------------------------------------------------------------------------- 1 | [Service] 2 | Host = "192.168.86.143" 3 | Port = 49991 4 | ConnectRetries = 3 5 | HealthCheck = "" 6 | StartupMsg = "device RPI started" 7 | ReadMaxLimit = 256 8 | Timeout = 5000 9 | 10 | [Clients] 11 | [Clients.Data] 12 | Host = "192.168.86.32" 13 | Port = 48080 14 | 15 | [Clients.Metadata] 16 | Host = "192.168.86.32" 17 | Port = 48081 18 | 19 | [Device] 20 | DataTransform = true 21 | Discovery = false 22 | InitCmd = "" 23 | InitCmdArgs = "" 24 | MaxCmdOps = 128 25 | MaxCmdResultLen = 256 26 | RemoveCmd = "" 27 | RemoveCmdArgs = "" 28 | ProfilesDir = "" 29 | SendReadingsOnChanged = true 30 | 31 | [Logging] 32 | RemoteURL = "" 33 | File = "-" 34 | 35 | [[DeviceList]] 36 | Name = "RPiBlinkLed" 37 | Profile = "RPi_Blink_Led" 38 | Description = "LED control using RPi's GPIO pins" 39 | Labels = [ "RPi Example" ] 40 | [DeviceList.Protocols.GPIO] 41 | Address = "GPIO" 42 | -------------------------------------------------------------------------------- /Build-Docker.md: -------------------------------------------------------------------------------- 1 | ## Build Docker image: 2 | 3 | 1. Check out edgex-device-rpi repo: 4 | ``` 5 | git clone https://github.com/mhall119/edgex-device-rpi 6 | ``` 7 | 8 | 2. Install docker tools from upstream (see [instructions here](https://docs.docker.com/install/linux/docker-ce/debian/)) 9 | 10 | You may also need to add your user to the `docker` group: 11 | ``` 12 | sudo usermod -a -G docker $USER 13 | newgrp docker 14 | ``` 15 | 16 | 3. Build a docker image by using the following command 17 | ``` 18 | cd edgex-device-rpi 19 | docker build . -t edgex-device-rpi -f ./scripts/Dockerfile.alpine-3.8 20 | 21 | ``` 22 | This command will build the edgex-device-rpi release image. 23 | By default, the configuration and profile file used by the service are available in `res` folder, but you can override 24 | that by passing in the `./examples/` path you want to use. See the [Example Projects](#example-projects) below for more. 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /scripts/build_deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e -x 3 | 4 | EDGEX_SDK_VERSION=1.0.2 5 | # Dependencies 6 | if [ ! -d deps ] 7 | then 8 | ROOT=$(dirname $(dirname $(readlink -f $0))) 9 | echo $ROOT 10 | cd $ROOT 11 | 12 | mkdir deps 13 | 14 | cd $ROOT/deps 15 | 16 | git clone https://github.com/intel-iot-devkit/mraa.git 17 | cd mraa 18 | # This version contain fix to identify raspberry-pi 3 19 | git reset --hard d320776 20 | 21 | # patch for raspberryPI 22 | patch -p1 < $ROOT/scripts/rpi_patch 23 | 24 | mkdir -p build && cd build 25 | 26 | # always install in lib folder 27 | cmake -DBUILDSWIG=OFF -DCMAKE_INSTALL_LIBDIR=lib ../. 28 | make && make install 29 | 30 | # get c-sdk from edgexfoundry 31 | cd $ROOT/deps 32 | wget https://github.com/edgexfoundry/device-sdk-c/archive/v${EDGEX_SDK_VERSION}.tar.gz 33 | tar -xzf v${EDGEX_SDK_VERSION}.tar.gz 34 | cd device-sdk-c-${EDGEX_SDK_VERSION} 35 | ./scripts/build.sh 36 | cp -rf include/* /usr/include/ 37 | cp build/release/c/libcsdk.so /usr/lib/ 38 | 39 | rm -rf $basesdir/deps 40 | fi 41 | -------------------------------------------------------------------------------- /examples/MotionDetector/configuration.toml: -------------------------------------------------------------------------------- 1 | [Service] 2 | Host = "192.168.86.21" 3 | Port = 49991 4 | ConnectRetries = 3 5 | HealthCheck = "" 6 | StartupMsg = "device RPI started" 7 | ReadMaxLimit = 256 8 | Timeout = 5000 9 | 10 | [Clients] 11 | [Clients.Data] 12 | Host = "192.168.86.32" 13 | Port = 48080 14 | 15 | [Clients.Metadata] 16 | Host = "192.168.86.32" 17 | Port = 48081 18 | 19 | [Device] 20 | DataTransform = true 21 | Discovery = false 22 | InitCmd = "" 23 | InitCmdArgs = "" 24 | MaxCmdOps = 128 25 | MaxCmdResultLen = 256 26 | RemoveCmd = "" 27 | RemoveCmdArgs = "" 28 | ProfilesDir = "" 29 | SendReadingsOnChanged = true 30 | 31 | [Logging] 32 | RemoteURL = "" 33 | File = "-" 34 | 35 | [[DeviceList]] 36 | Name = "RPiMotionDetector" 37 | Profile = "RPi_Motion_Detector" 38 | Description = "Motion detector using RPi's GPIO pins and a PIR sensor" 39 | Labels = [ "RPi Example" ] 40 | [DeviceList.Protocols.GPIO] 41 | Address = "GPIO" 42 | [[DeviceList.AutoEvents]] 43 | Frequency="1s" 44 | OnChange = false 45 | Resource = "Get_MotionState" 46 | -------------------------------------------------------------------------------- /examples/Blink/RPi_Blink_Led.yaml: -------------------------------------------------------------------------------- 1 | name: "RPi_Blink_Led" 2 | manufacturer: "EdgeX Foundry" 3 | model: "" 4 | labels: 5 | - "Example using GPIO on a Raspberry Pi" 6 | description: "Control an LED from a RaspberryPi" 7 | deviceResources: 8 | - name: LED 9 | description: "Turn the LED to On/Off" 10 | attributes: 11 | { Pin_Num: "11", Interface: "GPIO", Type: "OUT" } 12 | properties: 13 | value: 14 | { type: "Bool", readWrite: "RW", size: "1", minimum: "0", maximum: "1", defaultValue: "0" } 15 | units: 16 | { type: "String", readWrite: "R", defaultValue: "Enabled/Disabled" } 17 | 18 | deviceCommands: 19 | - name: Set_Led 20 | set: 21 | - { operation: "set", object: "LED", property: "value", parameter: "LED" } 22 | 23 | coreCommands: 24 | - name: Set_Led 25 | put: 26 | path: "/api/v1/device/{deviceId}/Set_Led" 27 | parameterNames: ["LED"] 28 | responses: 29 | - code: "204" 30 | description: "valid and accepted" 31 | expectedValues: [] 32 | - code: "400" 33 | description: "bad request" 34 | expectedValues: [] 35 | - code: "503" 36 | description: "service unavailable" 37 | expectedValues: [] 38 | 39 | -------------------------------------------------------------------------------- /scripts/Dockerfile.alpine-3.8: -------------------------------------------------------------------------------- 1 | FROM alpine:3.8 as builder 2 | MAINTAINER Michael Hall 3 | RUN apk add --update --no-cache build-base git gcc cmake make linux-headers yaml-dev libmicrohttpd-dev curl-dev 4 | 5 | COPY scripts /device-rpi/scripts 6 | COPY src /device-rpi/src/ 7 | RUN mkdir -p /device-rpi/build 8 | 9 | WORKDIR /device-rpi 10 | RUN /device-rpi/scripts/build_deps.sh 11 | RUN /device-rpi/scripts/build.sh 12 | 13 | FROM alpine:3.8 14 | 15 | RUN apk add --update --no-cache linux-headers yaml libmicrohttpd curl-dev 16 | 17 | COPY --from=builder /device-rpi/build/release/device-rpi /device-rpi/build/release/ 18 | COPY --from=builder /usr/lib/libcsdk.so /usr/lib 19 | COPY --from=builder /usr/include/edgex /usr/include/edgex 20 | COPY --from=builder /usr/include/thpool.h /usr/include/thpool.h 21 | COPY --from=builder /usr/include/iot /usr/include/iot 22 | COPY --from=builder /usr/local/include/mraa /usr/local/include/ 23 | COPY --from=builder /usr/local/include/mraa.h /usr/local/include/ 24 | COPY --from=builder /usr/local/lib/libmraa.so* /usr/local/lib/ 25 | 26 | COPY LICENSE /device-rpi/ 27 | COPY res /device-rpi/res/ 28 | COPY examples /device-rpi/examples 29 | 30 | ENTRYPOINT ["/device-rpi/build/release/device-rpi", "-c"] 31 | CMD ["/device-rpi/res/"] 32 | -------------------------------------------------------------------------------- /scripts/rpi_patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/arm/arm.c b/src/arm/arm.c 2 | index 62d6b2e..73dc07a 100644 3 | --- a/src/arm/arm.c 4 | +++ b/src/arm/arm.c 5 | @@ -104,6 +104,12 @@ mraa_arm_platform() 6 | platform_type = MRAA_RASPBERRY_PI; 7 | } 8 | 9 | + /* Forcing the platform type as dtb is not generated for arm64 */ 10 | + if (platform_type == MRAA_UNKNOWN_PLATFORM) 11 | + { 12 | + platform_type = MRAA_RASPBERRY_PI; 13 | + } 14 | + 15 | switch (platform_type) { 16 | case MRAA_RASPBERRY_PI: 17 | plat = mraa_raspberry_pi(); 18 | diff --git a/src/arm/raspberry_pi.c b/src/arm/raspberry_pi.c 19 | index 0a35166..c5627b3 100644 20 | --- a/src/arm/raspberry_pi.c 21 | +++ b/src/arm/raspberry_pi.c 22 | @@ -578,6 +578,13 @@ mraa_raspberry_pi() 23 | platform_detected = PLATFORM_RASPBERRY_PI3_B_PLUS; 24 | b->phy_pin_count = MRAA_RASPBERRY_PI3_B_PLUS_PINCOUNT; 25 | } 26 | + else 27 | + { 28 | + /* Forcing the platform type as dtb is not generated for arm64 */ 29 | + b->platform_name = PLATFORM_NAME_RASPBERRY_PI3_B_PLUS; 30 | + platform_detected = PLATFORM_RASPBERRY_PI3_B_PLUS; 31 | + b->phy_pin_count = MRAA_RASPBERRY_PI3_B_PLUS_PINCOUNT; 32 | + } 33 | } 34 | 35 | b->aio_count = 0; 36 | -------------------------------------------------------------------------------- /src/c/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(device_rpi LANGUAGES C) 3 | 4 | # Package support 5 | set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) 6 | 7 | find_package (LibMRAA REQUIRED) 8 | if (NOT LIBMRAA_FOUND) 9 | message (WARNING "mraa library or header not found") 10 | endif () 11 | 12 | find_package (Libcsdk REQUIRED) 13 | if (NOT LIBCSDK_FOUND) 14 | message (WARNING "csdk library or header not found") 15 | endif () 16 | 17 | # Set additional C compiler flags 18 | if (DEFINED CMAKE_C_COMPILER_ID) 19 | if (CMAKE_C_COMPILER_ID MATCHES GNU) 20 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wstrict-prototypes -Wmissing-prototypes") 21 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") 22 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE") 23 | set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -O0") 24 | set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -ggdb -O0") 25 | set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -DNDEBUG") 26 | set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -O3") 27 | endif () 28 | endif () 29 | 30 | file (GLOB C_FILES *.c) 31 | find_library(EDGEX_CSDK_RELEASE_LIB NAMES csdk) 32 | find_library(LIBMRAA_LIB NAMES mraa) 33 | add_executable(device-rpi ${C_FILES}) 34 | target_include_directories (device-rpi PRIVATE .) 35 | target_link_libraries (device-rpi PUBLIC m PRIVATE ${LIBMRAA_LIB} ${EDGEX_CSDK_RELEASE_LIB}) 36 | install(TARGETS device-rpi DESTINATION bin) -------------------------------------------------------------------------------- /src/c/device_rpi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 3 | * IoTech Ltd 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | * 7 | */ 8 | 9 | #ifndef _DEVICE_RPI_H_ 10 | #define _DEVICE_RPI_H_ 1 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include "edgex/edgex.h" 19 | #include "edgex/devsdk.h" 20 | #include "edgex/device-mgmt.h" 21 | 22 | #if defined (__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | 27 | #define RPI_ERR_CHECK(x) if (x.code) { fprintf (stderr, "Error: %d: %s\n", x.code, x.reason); return x.code; } 28 | #define RPI_NO_GPIO_PINS 7 29 | #define RPI_NO_AIO_PINS 0 30 | #define RPI_NO_I2C_PINS 0 31 | #define RPI_NO_PORTS RPI_NO_GPIO_PINS + RPI_NO_AIO_PINS + RPI_NO_I2C_PINS 32 | 33 | #define RPI_I2C_BUS 0 34 | 35 | #define RPI_ROTARY_MAX_ANGLE 300 36 | #define RPI_ADC_REF 5 37 | 38 | #define RPI_SVC "Device-RPi" 39 | 40 | typedef enum 41 | { 42 | RPI_GPIO = 0, 43 | RPI_PWM = 1, 44 | RPI_AIO = 2, 45 | RPI_I2C = 3, 46 | RPI_SERIAL = 4 47 | } rpi_interface_type_t; 48 | 49 | typedef struct 50 | { 51 | char *pin_no; 52 | char *pin_type; 53 | char *type; 54 | bool normalize; 55 | } rpi_attributes_t; 56 | 57 | typedef struct 58 | { 59 | bool is_lcd; 60 | mraa_i2c_context dev; 61 | mraa_i2c_context rgb_dev; 62 | } rpi_i2c_dev_ctxt_t; 63 | 64 | typedef struct 65 | { 66 | rpi_interface_type_t pin_type; 67 | char *pin_number; 68 | void *dev_ctxt; 69 | } rpi_dev_ctxt_t; 70 | 71 | typedef struct 72 | { 73 | iot_logger_t *lc; 74 | edgex_device_service *svc; 75 | rpi_dev_ctxt_t *dev[RPI_NO_PORTS]; 76 | pthread_mutex_t mutex; 77 | } rpi_pidriver_t; 78 | 79 | #if defined (__cplusplus) 80 | } 81 | #endif 82 | #endif 83 | -------------------------------------------------------------------------------- /examples/Blink/README.md: -------------------------------------------------------------------------------- 1 | # Blink LED Example 2 | 3 | ## About 4 | Example lighting control using an LED and Node-Red 5 | 6 | ## Hardware: 7 | * 1 LED 8 | * 2 220ohm resisters 9 | 10 | ## Configuration 11 | 12 | Connect the LED as shown below. 13 | 14 | ![Wiring Diagram](wiring.png) 15 | 16 | * The LED should be connected to pin #11 on the Pi 17 | 18 | ## Running 19 | 20 | ### Start EdgeX 21 | 22 | While you can run EdgeX on a RaspberryPi, due to it's limited resources it's best to run the EdgeX services on your PC or another computer. 23 | 24 | Use the docker-compose.yaml file provided in this example project to launch an EdgeX stack 25 | 26 | ``` 27 | docker-compose -f ./examples/Blink/docker-compose.yaml up -d 28 | ``` 29 | 30 | This file also includes Node Red, which is used later in this example. 31 | 32 | ### Run the device service 33 | 34 | Before running `device-rpi` for this example, you will need to change its `configuration.toml` to point to the 35 | IP address of your RaspberryPi as well as the IP address of your running EdgeX services. 36 | 37 | At the top of the file, replace the `Host` property with the IP address of your RaspberryPi 38 | 39 | ![Service Configuration](config_service.png) 40 | 41 | In the `[Clients]` section, update the `Host` properties for Data and Metadata with the IP address 42 | of the machine running the EdgeX services you started in the first step. 43 | 44 | ![Clients Configuration](config_clients.png) 45 | 46 | Then you can start the `device-rpi` service using using the `Blink ` example: 47 | ``` 48 | ./build/release/device-rpi --confdir ./examples/Blink 49 | ``` 50 | 51 | ### Configure Node-Red 52 | 53 | A Node-Red flow is provided for this example, you will need to load it into your instance. 54 | 55 | 1. Open http://localhost:1880/ on the the machine running your EdgeX services (or replace `localhost` with that machine's IP address) 56 | 57 | 2. Import the example Node-Red configuration by copy/pasting the provided `blinkr_flow.json` file into your instance: 58 | 59 | ![Import from Clipboard](nodered_clipboard.png) 60 | ![Import Flow](nodered_import.png) 61 | 62 | 3. Click the `Deploy` button at the top of your Node-Red screen to start your flow 63 | 64 | ## Testing 65 | 66 | You will now have a Node-Red dashboard at http://localhost:1880/ui/ where you can control the LED on your board. 67 | 68 | ![Node-Red Dashboard](nodered_dashboard.png) 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Device RaspberryPi GPIO Service 2 | 3 | ## About 4 | The EdgeX RaspberryPi Device Service is developed to control/communicate with sensors connected the GPIO pins on a RaspberryPi 5 | 6 | ## Supported Boards: 7 | Raspberry PI 3+ 8 | - Ubuntu 18.04 64bit 9 | - Raspbian Stretch 32bit 10 | 11 | ## Dependencies: 12 | 13 | You will also need some build tools to compile and run the Device RaspberryPi service. 14 | On Rasbian or Ubuntu, these can be installed with: 15 | ``` 16 | sudo apt install git cmake curl g++ libcurl4-openssl-dev libmicrohttpd-dev libyaml-dev uuid-dev 17 | ``` 18 | 19 | You will also need `libcbor-dev`, which is not available in the latest stable Raspbian release. You can manually download and install it with: 20 | ``` 21 | wget http://ftp.us.debian.org/debian/pool/main/libc/libcbor/libcbor0_0.5.0+dfsg-2_armhf.deb 22 | sudo dpkg -i libcbor0_0.5.0+dfsg-2_armhf.deb 23 | wget http://ftp.us.debian.org/debian/pool/main/libc/libcbor/libcbor-dev_0.5.0+dfsg-2_armhf.deb 24 | sudo dpkg -i libcbor-dev_0.5.0+dfsg-2_armhf.deb 25 | ``` 26 | 27 | ## Build Instruction: 28 | 29 | 1. Check out edgex-device-rpi repo: 30 | ``` 31 | git clone https://github.com/mhall119/edgex-device-rpi 32 | cd edgex-device-rpi 33 | ``` 34 | 35 | 2. Download and build the dependencies: 36 | ``` 37 | sudo ./scripts/build_deps.sh 38 | ``` 39 | This command will download and build both the `libmraa` and `device-c-sdk` libraries needed to build the edgex-device-rpi executable. 40 | 41 | 3. Build the executable: 42 | ``` 43 | ./scripts/build.sh 44 | ``` 45 | 46 | You can then run the device service using one of the example configurations in the [./examples/](./examples/) folder with: 47 | ``` 48 | ./build/release/device-rpi --confdir ./examples/ 49 | ``` 50 | 51 | Be sure to read and follow the setup instructions for the example project before running `device-rpi`. See the [Example Projects](#example-projects) below for more. 52 | 53 | ## Example Projects 54 | 55 | The EdgeX RaspberryPi Device Service comes with some pre-defined examples you can use to get started. 56 | These projects include instructions for running EdgeX services on your PC, running the RPi service on your device, wiring diagrams for connecting sensors, and configuration files for controlling everything. 57 | 58 | Available exampless are: 59 | - [LED Control](examples/Blink/README.md) 60 | - [Motion Detector](examples/MotionDetector/README.md) 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /examples/MotionDetector/RPi_Motion_Detector.yaml: -------------------------------------------------------------------------------- 1 | name: "RPi_Motion_Detector" 2 | manufacturer: "EdgeX Foundry" 3 | model: "" 4 | labels: 5 | - "Example using GPIO on a Raspberry Pi" 6 | description: "Control an LED and PIR sensor from a RaspberryPi" 7 | deviceResources: 8 | - name: Green_LED 9 | description: "Turn the Green LED to On/Off" 10 | attributes: 11 | { Pin_Num: "11", Interface: "GPIO", Type: "OUT" } 12 | properties: 13 | value: 14 | { type: "Bool", readWrite: "RW", size: "1", minimum: "0", maximum: "1", defaultValue: "0" } 15 | units: 16 | { type: "String", readWrite: "R", defaultValue: "Enabled/Disabled" } 17 | 18 | - name: Red_LED 19 | description: "Turn the Red LED to On/Off" 20 | attributes: 21 | { Pin_Num: "12", Interface: "GPIO", Type: "OUT" } 22 | properties: 23 | value: 24 | { type: "Bool", readWrite: "RW", size: "1", minimum: "0", maximum: "1", defaultValue: "0" } 25 | units: 26 | { type: "String", readWrite: "R", defaultValue: "Enabled/Disabled" } 27 | 28 | - name: MotionState 29 | description: "HIGH when motion is detected and LOW when absent" 30 | attributes: 31 | { Pin_Num: "7", Interface: "GPIO", Type: "IN" } 32 | properties: 33 | value: 34 | { type: "Uint8", readWrite: "RW", size: "1", minimum: "0", maximum: "1", defaultValue: "0" } 35 | units: 36 | { type: "String", readWrite: "R", defaultValue: " " } 37 | 38 | deviceCommands: 39 | - name: Set_Green_Led 40 | set: 41 | - { operation: "set", object: "Green_LED", property: "value", parameter: "Green_LED" } 42 | 43 | - name: Set_Red_Led 44 | set: 45 | - { operation: "set", object: "Red_LED", property: "value", parameter: "Red_LED" } 46 | 47 | - name: Get_MotionState 48 | get: 49 | - { operation: "get", object: "MotionState", property: "value", parameter: "MotionState" } 50 | 51 | coreCommands: 52 | - name: Set_Green_Led 53 | put: 54 | path: "/api/v1/device/{deviceId}/Set_Green_Led" 55 | parameterNames: ["Green_LED"] 56 | responses: 57 | - code: "204" 58 | description: "valid and accepted" 59 | expectedValues: [] 60 | - code: "400" 61 | description: "bad request" 62 | expectedValues: [] 63 | - code: "503" 64 | description: "service unavailable" 65 | expectedValues: [] 66 | 67 | - name: Set_Red_Led 68 | put: 69 | path: "/api/v1/device/{deviceId}/Set_Red_Led" 70 | parameterNames: ["Red_LED"] 71 | responses: 72 | - code: "204" 73 | description: "valid and accepted" 74 | expectedValues: [] 75 | - code: "400" 76 | description: "bad request" 77 | expectedValues: [] 78 | - code: "503" 79 | description: "service unavailable" 80 | expectedValues: [] 81 | 82 | - name: Get_MotionState 83 | get: 84 | path: "/api/v1/device/{deviceId}/Get_MotionState" 85 | responses: 86 | - code: "200" 87 | description: "valid and accepted" 88 | expectedValues: ["MotionState"] 89 | - code: "503" 90 | description: "service unavailable" 91 | expectedValues: [] 92 | 93 | 94 | -------------------------------------------------------------------------------- /examples/MotionDetector/README.md: -------------------------------------------------------------------------------- 1 | # Motion Detector Example 2 | 3 | ## About 4 | Example of a motion detector using a PIR sensor, LEDs and Node-Red 5 | 6 | ## Hardware: 7 | * 1 PIR sensor 8 | * 1 Green LED 9 | * 1 Red LED 10 | * 2 220ohm resisters 11 | 12 | ## Configuration 13 | 14 | Connect the LEDs and PIR sensor as shown below. 15 | 16 | ![Wiring Diagram](wiring.png) 17 | 18 | * Make sure that the PIR sensor is connected to the 5v pin and not the 3.3v pin on the Raspberry Pi 19 | 20 | * The output pin on the PIR should be connected to pin #7 on the Raspberry Pi. 21 | 22 | * The Green LED should be connected to pin #11 on the Pi, and the Red LED connected to pin #12 23 | 24 | ## Running 25 | 26 | ### Start EdgeX 27 | 28 | While you can run EdgeX on a RaspberryPi, due to it's limited resources it's best to run the EdgeX services on your PC or another computer. 29 | 30 | Use the docker-compose.yaml file provided in this example project to launch an EdgeX stack 31 | 32 | ``` 33 | docker-compose -f ./examples/MotionDetector/docker-compose.yaml up -d 34 | ``` 35 | 36 | This file also includes Mosquitto MQTT broker and Node Red, both of which are used later in this example. 37 | 38 | ### Run the device service 39 | 40 | Before running `device-rpi` for this example, you will need to change its `configuration.toml` to point to the 41 | IP address of your RaspberryPi as well as the IP address of your running EdgeX services. 42 | 43 | At the top of the file, replace the `Host` property with the IP address of your RaspberryPi 44 | 45 | ![Service Configuration](config_service.png) 46 | 47 | In the `[Clients]` section, update the `Host` properties for Data and Metadata with the IP address 48 | of the machine running the EdgeX services you started in the first step. 49 | 50 | ![Clients Configuration](config_clients.png) 51 | 52 | Then you can start the `device-rpi` service using using the `MotionDetector ` example: 53 | ``` 54 | ./build/release/device-rpi --confdir ./examples/MotionDetector 55 | ``` 56 | 57 | ### Configure Node-Red 58 | 59 | A Node-Red flow is provided for this example, you will need to load it into your instance. 60 | 61 | 1. Open http://localhost:1880/ on the the machine running your EdgeX services (or replace `localhost` with that machine's IP address) 62 | 63 | 2. Import the example Node-Red configuration by copy/pasting the provided `motion_detector_flow.json` file into your instance: 64 | 65 | ![Import from Clipboard](nodered_clipboard.png) 66 | ![Import Flow](nodered_import.png) 67 | 68 | 3. Click the `Deploy` button at the top of your Node-Red screen to start your flow 69 | 70 | 71 | ### Export device service readings to Node-Red 72 | 73 | Finally, you need to tell your EdgeX instance to export data from `device-rpi` to Node-Red. 74 | This example uses the Mosquitto MQTT broker to link the two. 75 | 76 | Run the `register_mqtt_export.sh` script on the machine running your EdgeX services (or replace `localhost` at the end of that script with that machine's IP address) 77 | 78 | ``` 79 | ./register_mqtt_export.sh 80 | ``` 81 | 82 | ## Testing 83 | 84 | You will now have a Node-Red dashboard at http://localhost:1880/ui/ where you can watch motion events come in and also control the Red LED on your board. 85 | 86 | ![Node-Red Dashboard](nodered_dashboard.png) 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /snap/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: edgex-device-rpi 2 | base: core18 3 | version: '0.1' 4 | summary: Connect to GPIO pins on RasPi with EdgeX 5 | description: | 6 | The EdgeX Device RaspberryPi Service is developed to control/communicate 7 | with sensors connected the GPIO pins on a RaspberryPi 8 | 9 | architectures: 10 | - build-on: arm64 11 | run-on: arm64 12 | - build-on: armhf 13 | run-on: armhf 14 | 15 | grade: stable 16 | confinement: strict 17 | 18 | apps: 19 | edgex-device-rpi: 20 | command: bin/device-rpi 21 | plugs: 22 | - home 23 | - removable-media 24 | - network 25 | - network-bind 26 | - gpio 27 | 28 | parts: 29 | examples: 30 | source: . 31 | plugin: dump 32 | organize: 33 | LICENSE: usr/share/doc/edgex-device-rpi/LICENSE 34 | prime: 35 | - examples/* 36 | - usr/share/doc/edgex-device-rpi/LICENSE 37 | stage: 38 | - examples/* 39 | - usr/share/doc/edgex-device-rpi/LICENSE 40 | stage-patches: 41 | source: . 42 | after: [examples] 43 | plugin: dump 44 | organize: 45 | LICENSE: usr/share/doc/edgex-device-rpi/LICENSE 46 | prime: [-*] 47 | stage: [scripts/rpi_patch] 48 | libmraa: 49 | source: https://github.com/intel-iot-devkit/mraa.git 50 | source-commit: d320776 51 | plugin: cmake 52 | configflags: 53 | - -DBUILDSWIG=OFF 54 | after: [stage-patches] 55 | override-build: | 56 | cd $SNAPCRAFT_PART_SRC 57 | patch -p1 < $SNAPCRAFT_STAGE/scripts/rpi_patch 58 | snapcraftctl build 59 | prime: 60 | - lib/libmraa* 61 | build-packages: 62 | - g++ 63 | tomlc99: 64 | source: https://github.com/IOTechSystems/tomlc99.git 65 | source-tag: SDK-0.2 66 | source-depth: 1 67 | plugin: dump 68 | organize: 69 | toml.c: src/c/toml.c 70 | toml.h: src/c/toml.h 71 | stage: 72 | - src/c 73 | prime: [-*] 74 | iotech-c-utils: 75 | source: https://github.com/IOTechSystems/iotech-c-utils.git 76 | source-tag: v0.1.3 77 | source-depth: 1 78 | plugin: dump 79 | stage: 80 | - src/c/scheduler.c 81 | - src/c/logging.c 82 | - include/iot 83 | prime: [-*] 84 | c-thread-pool: 85 | source: https://github.com/IOTechSystems/C-Thread-Pool.git 86 | source-tag: SDK-0.1 87 | source-depth: 1 88 | plugin: dump 89 | organize: 90 | thpool.c: src/c/thpool.c 91 | thpool.h: include/thpool.h 92 | stage: 93 | - src/c/thpool.c 94 | - include/thpool.h 95 | prime: [-*] 96 | device-sdk-c: 97 | after: 98 | - tomlc99 99 | - c-thread-pool 100 | - iotech-c-utils 101 | plugin: cmake 102 | configflags: 103 | - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 104 | - -DCMAKE_BUILD_TYPE=Release 105 | source: https://github.com/edgexfoundry/device-sdk-c.git 106 | source-branch: delhi 107 | source-subdir: src 108 | override-build: | 109 | # copy all of the dep sources from $SNAPCRAFT_STAGE into the build folder 110 | cd $SNAPCRAFT_PART_SRC 111 | cp -r $SNAPCRAFT_STAGE/src/c/* src/c/ 112 | cp -r $SNAPCRAFT_STAGE/include/* include/ 113 | snapcraftctl build 114 | build-packages: 115 | - libcurl4-openssl-dev 116 | - libmicrohttpd-dev 117 | - libyaml-dev 118 | edgex-device-rpi: 119 | source: . 120 | plugin: cmake 121 | source-subdir: src/c 122 | after: 123 | - device-sdk-c 124 | - libmraa 125 | configflags: 126 | - -DCMAKE_BUILD_TYPE=Release 127 | pkgs: 128 | plugin: nil 129 | stage-packages: 130 | - libcurl4-openssl-dev 131 | - libmicrohttpd-dev 132 | - libyaml-dev 133 | - curl 134 | -------------------------------------------------------------------------------- /examples/Blink/blink_flow.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "c015ae9e.0c0f4", 4 | "type": "tab", 5 | "label": "EdgeX RPi Blink Example" 6 | }, 7 | { 8 | "id": "1b8e6270.68f5ae", 9 | "type": "http request", 10 | "z": "c015ae9e.0c0f4", 11 | "name": "Set LED", 12 | "method": "PUT", 13 | "ret": "txt", 14 | "url": "http://edgex-core-command:48082/api/v1/device/name/RPiBlinkLed/command/Set_Led", 15 | "tls": "", 16 | "x": 1180, 17 | "y": 420, 18 | "wires": [ 19 | [] 20 | ] 21 | }, 22 | { 23 | "id": "609114a1.cb640c", 24 | "type": "inject", 25 | "z": "c015ae9e.0c0f4", 26 | "name": "", 27 | "topic": "", 28 | "payload": "false", 29 | "payloadType": "bool", 30 | "repeat": "", 31 | "crontab": "", 32 | "once": false, 33 | "x": 169, 34 | "y": 221, 35 | "wires": [ 36 | [ 37 | "f7ae0719.6aea78" 38 | ] 39 | ] 40 | }, 41 | { 42 | "id": "f7ae0719.6aea78", 43 | "type": "ui_switch", 44 | "z": "c015ae9e.0c0f4", 45 | "name": "", 46 | "label": "LED Switch", 47 | "group": "2dd8d9a.215e326", 48 | "order": 0, 49 | "width": 0, 50 | "height": 0, 51 | "passthru": true, 52 | "decouple": "false", 53 | "topic": "", 54 | "style": "", 55 | "onvalue": "true", 56 | "onvalueType": "bool", 57 | "onicon": "", 58 | "oncolor": "", 59 | "offvalue": "false", 60 | "offvalueType": "bool", 61 | "officon": "", 62 | "offcolor": "", 63 | "x": 447, 64 | "y": 322, 65 | "wires": [ 66 | [ 67 | "c1d868ae.0c88f8" 68 | ] 69 | ] 70 | }, 71 | { 72 | "id": "c1d868ae.0c88f8", 73 | "type": "switch", 74 | "z": "c015ae9e.0c0f4", 75 | "name": "Enable LED", 76 | "property": "payload", 77 | "propertyType": "msg", 78 | "rules": [ 79 | { 80 | "t": "true" 81 | }, 82 | { 83 | "t": "false" 84 | } 85 | ], 86 | "checkall": "true", 87 | "outputs": 2, 88 | "x": 716, 89 | "y": 378, 90 | "wires": [ 91 | [ 92 | "648b2aa6.963104" 93 | ], 94 | [ 95 | "1667b567.52e3fb" 96 | ] 97 | ] 98 | }, 99 | { 100 | "id": "648b2aa6.963104", 101 | "type": "function", 102 | "z": "c015ae9e.0c0f4", 103 | "name": "Turn on LED", 104 | "func": "var data = {}\ndata[\"LED\"] = \"true\"\nmsg.payload = JSON.stringify (data);\nreturn msg;", 105 | "outputs": 1, 106 | "noerr": 0, 107 | "x": 946, 108 | "y": 358, 109 | "wires": [ 110 | [ 111 | "1b8e6270.68f5ae", 112 | "95f847ce.93caa8" 113 | ] 114 | ] 115 | }, 116 | { 117 | "id": "1667b567.52e3fb", 118 | "type": "function", 119 | "z": "c015ae9e.0c0f4", 120 | "name": "Turn off LED", 121 | "func": "var data = {}\ndata[\"LED\"] = \"false\"\nmsg.payload = JSON.stringify (data);\nreturn msg;", 122 | "outputs": 1, 123 | "noerr": 0, 124 | "x": 950, 125 | "y": 480, 126 | "wires": [ 127 | [ 128 | "1b8e6270.68f5ae", 129 | "95f847ce.93caa8" 130 | ] 131 | ] 132 | }, 133 | { 134 | "id": "95f847ce.93caa8", 135 | "type": "debug", 136 | "z": "c015ae9e.0c0f4", 137 | "name": "", 138 | "active": true, 139 | "console": "false", 140 | "complete": "false", 141 | "x": 1183, 142 | "y": 558, 143 | "wires": [] 144 | }, 145 | { 146 | "id": "2dd8d9a.215e326", 147 | "type": "ui_group", 148 | "z": "", 149 | "name": "RPi Blink Example", 150 | "tab": "7c6a217.7b196e", 151 | "disp": true, 152 | "width": "6" 153 | }, 154 | { 155 | "id": "7c6a217.7b196e", 156 | "type": "ui_tab", 157 | "z": "", 158 | "name": "EdgeX Device RPi Examples", 159 | "icon": "dashboard" 160 | } 161 | ] -------------------------------------------------------------------------------- /examples/Blink/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # /******************************************************************************* 2 | # * Copyright 2019 EdgeX Foundry 3 | # * 4 | # * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | # * in compliance with the License. You may obtain a copy of the License at 6 | # * 7 | # * http://www.apache.org/licenses/LICENSE-2.0 8 | # * 9 | # * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | # * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | # * or implied. See the License for the specific language governing permissions and limitations under 12 | # * the License. 13 | # * 14 | # * @author: Michael Hall 15 | # * EdgeX Foundry, Edinburgh, version 1.0.1 16 | # * added: July 18, 2019 17 | # *******************************************************************************/ 18 | 19 | version: '3' 20 | volumes: 21 | db-data: 22 | log-data: 23 | consul-config: 24 | consul-data: 25 | portainer_data: 26 | 27 | services: 28 | volume: 29 | image: edgexfoundry/docker-edgex-volume:1.0.0 30 | container_name: edgex-files 31 | networks: 32 | - edgex-network 33 | volumes: 34 | - db-data:/data/db 35 | - log-data:/edgex/logs 36 | - consul-config:/consul/config 37 | - consul-data:/consul/data 38 | 39 | consul: 40 | image: consul:1.3.1 41 | ports: 42 | - "8400:8400" 43 | - "8500:8500" 44 | - "8600:8600" 45 | container_name: edgex-core-consul 46 | hostname: edgex-core-consul 47 | networks: 48 | edgex-network: 49 | aliases: 50 | - edgex-core-consul 51 | volumes: 52 | - db-data:/data/db 53 | - log-data:/edgex/logs 54 | - consul-config:/consul/config 55 | - consul-data:/consul/data 56 | depends_on: 57 | - volume 58 | 59 | config-seed: 60 | image: edgexfoundry/docker-core-config-seed-go:1.0.0 61 | container_name: edgex-config-seed 62 | hostname: edgex-core-config-seed 63 | networks: 64 | edgex-network: 65 | aliases: 66 | - edgex-core-config-seed 67 | volumes: 68 | - db-data:/data/db 69 | - log-data:/edgex/logs 70 | - consul-config:/consul/config 71 | - consul-data:/consul/data 72 | depends_on: 73 | - volume 74 | - consul 75 | 76 | mongo: 77 | image: edgexfoundry/docker-edgex-mongo:1.0.1 78 | ports: 79 | - "27017:27017" 80 | container_name: edgex-mongo 81 | hostname: edgex-mongo 82 | networks: 83 | - edgex-network 84 | volumes: 85 | - db-data:/data/db 86 | - log-data:/edgex/logs 87 | - consul-config:/consul/config 88 | - consul-data:/consul/data 89 | depends_on: 90 | - volume 91 | 92 | logging: 93 | image: edgexfoundry/docker-support-logging-go:1.0.1 94 | ports: 95 | - "48061:48061" 96 | container_name: edgex-support-logging 97 | hostname: edgex-support-logging 98 | networks: 99 | - edgex-network 100 | volumes: 101 | - db-data:/data/db 102 | - log-data:/edgex/logs 103 | - consul-config:/consul/config 104 | - consul-data:/consul/data 105 | depends_on: 106 | - config-seed 107 | - mongo 108 | - volume 109 | 110 | notifications: 111 | image: edgexfoundry/docker-support-notifications-go:1.0.1 112 | ports: 113 | - "48060:48060" 114 | container_name: edgex-support-notifications 115 | hostname: edgex-support-notifications 116 | networks: 117 | - edgex-network 118 | volumes: 119 | - db-data:/data/db 120 | - log-data:/edgex/logs 121 | - consul-config:/consul/config 122 | - consul-data:/consul/data 123 | depends_on: 124 | - logging 125 | 126 | metadata: 127 | image: edgexfoundry/docker-core-metadata-go:1.0.1 128 | ports: 129 | - "48081:48081" 130 | container_name: edgex-core-metadata 131 | hostname: edgex-core-metadata 132 | networks: 133 | - edgex-network 134 | volumes: 135 | - db-data:/data/db 136 | - log-data:/edgex/logs 137 | - consul-config:/consul/config 138 | - consul-data:/consul/data 139 | depends_on: 140 | - logging 141 | 142 | data: 143 | image: edgexfoundry/docker-core-data-go:1.0.1 144 | ports: 145 | - "48080:48080" 146 | - "5563:5563" 147 | container_name: edgex-core-data 148 | hostname: edgex-core-data 149 | networks: 150 | - edgex-network 151 | volumes: 152 | - db-data:/data/db 153 | - log-data:/edgex/logs 154 | - consul-config:/consul/config 155 | - consul-data:/consul/data 156 | depends_on: 157 | - logging 158 | 159 | command: 160 | image: edgexfoundry/docker-core-command-go:1.0.1 161 | ports: 162 | - "48082:48082" 163 | container_name: edgex-core-command 164 | hostname: edgex-core-command 165 | networks: 166 | - edgex-network 167 | volumes: 168 | - db-data:/data/db 169 | - log-data:/edgex/logs 170 | - consul-config:/consul/config 171 | - consul-data:/consul/data 172 | depends_on: 173 | - metadata 174 | 175 | scheduler: 176 | image: edgexfoundry/docker-support-scheduler-go:1.0.1 177 | ports: 178 | - "48085:48085" 179 | container_name: edgex-support-scheduler 180 | hostname: edgex-support-scheduler 181 | networks: 182 | - edgex-network 183 | volumes: 184 | - db-data:/data/db 185 | - log-data:/edgex/logs 186 | - consul-config:/consul/config 187 | - consul-data:/consul/data 188 | depends_on: 189 | - metadata 190 | 191 | export-client: 192 | image: edgexfoundry/docker-export-client-go:1.0.1 193 | ports: 194 | - "48071:48071" 195 | container_name: edgex-export-client 196 | hostname: edgex-export-client 197 | networks: 198 | - edgex-network 199 | volumes: 200 | - db-data:/data/db 201 | - log-data:/edgex/logs 202 | - consul-config:/consul/config 203 | - consul-data:/consul/data 204 | depends_on: 205 | - data 206 | environment: 207 | - EXPORT_CLIENT_MONGO_URL=edgex-mongo 208 | - EXPORT_CLIENT_DISTRO_HOST=export-distro 209 | - EXPORT_CLIENT_CONSUL_HOST=edgex-config-seed 210 | 211 | export-distro: 212 | image: edgexfoundry/docker-export-distro-go:1.0.1 213 | ports: 214 | - "48070:48070" 215 | - "5566:5566" 216 | container_name: edgex-export-distro 217 | hostname: edgex-export-distro 218 | networks: 219 | - edgex-network 220 | volumes: 221 | - db-data:/data/db 222 | - log-data:/edgex/logs 223 | - consul-config:/consul/config 224 | - consul-data:/consul/data 225 | depends_on: 226 | - export-client 227 | environment: 228 | - EXPORT_DISTRO_CLIENT_HOST=export-client 229 | - EXPORT_DISTRO_DATA_HOST=edgex-core-data 230 | - EXPORT_DISTRO_CONSUL_HOST=edgex-config-seed 231 | - EXPORT_DISTRO_MQTTS_CERT_FILE=none 232 | - EXPORT_DISTRO_MQTTS_KEY_FILE=none 233 | 234 | 235 | ################################################################# 236 | # Application Services 237 | ################################################################# 238 | nodered: 239 | image: pomarc/node-red-dashboard 240 | ports: 241 | - 1880:1880 242 | container_name: edgex_nodered 243 | hostname: edgex-nodered 244 | networks: 245 | - edgex-network 246 | 247 | ################################################################# 248 | # Device Services 249 | ################################################################# 250 | 251 | 252 | ################################################################# 253 | # Tooling 254 | ################################################################# 255 | 256 | portainer: 257 | image: portainer/portainer 258 | ports: 259 | - "9000:9000" 260 | command: -H unix:///var/run/docker.sock 261 | volumes: 262 | - /var/run/docker.sock:/var/run/docker.sock 263 | - portainer_data:/data 264 | depends_on: 265 | - volume 266 | 267 | networks: 268 | edgex-network: 269 | driver: "bridge" 270 | ... 271 | -------------------------------------------------------------------------------- /examples/MotionDetector/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # /******************************************************************************* 2 | # * Copyright 2019 EdgeX Foundry 3 | # * 4 | # * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | # * in compliance with the License. You may obtain a copy of the License at 6 | # * 7 | # * http://www.apache.org/licenses/LICENSE-2.0 8 | # * 9 | # * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | # * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | # * or implied. See the License for the specific language governing permissions and limitations under 12 | # * the License. 13 | # * 14 | # * @author: Michael Hall 15 | # * EdgeX Foundry, Edinburgh, version 1.0.1 16 | # * added: July 18, 2019 17 | # *******************************************************************************/ 18 | 19 | version: '3' 20 | volumes: 21 | db-data: 22 | log-data: 23 | consul-config: 24 | consul-data: 25 | portainer_data: 26 | 27 | services: 28 | volume: 29 | image: edgexfoundry/docker-edgex-volume:1.0.0 30 | container_name: edgex-files 31 | networks: 32 | - edgex-network 33 | volumes: 34 | - db-data:/data/db 35 | - log-data:/edgex/logs 36 | - consul-config:/consul/config 37 | - consul-data:/consul/data 38 | 39 | consul: 40 | image: consul:1.3.1 41 | ports: 42 | - "8400:8400" 43 | - "8500:8500" 44 | - "8600:8600" 45 | container_name: edgex-core-consul 46 | hostname: edgex-core-consul 47 | networks: 48 | edgex-network: 49 | aliases: 50 | - edgex-core-consul 51 | volumes: 52 | - db-data:/data/db 53 | - log-data:/edgex/logs 54 | - consul-config:/consul/config 55 | - consul-data:/consul/data 56 | depends_on: 57 | - volume 58 | 59 | config-seed: 60 | image: edgexfoundry/docker-core-config-seed-go:1.0.0 61 | container_name: edgex-config-seed 62 | hostname: edgex-core-config-seed 63 | networks: 64 | edgex-network: 65 | aliases: 66 | - edgex-core-config-seed 67 | volumes: 68 | - db-data:/data/db 69 | - log-data:/edgex/logs 70 | - consul-config:/consul/config 71 | - consul-data:/consul/data 72 | depends_on: 73 | - volume 74 | - consul 75 | 76 | mongo: 77 | image: edgexfoundry/docker-edgex-mongo:1.0.1 78 | ports: 79 | - "27017:27017" 80 | container_name: edgex-mongo 81 | hostname: edgex-mongo 82 | networks: 83 | - edgex-network 84 | volumes: 85 | - db-data:/data/db 86 | - log-data:/edgex/logs 87 | - consul-config:/consul/config 88 | - consul-data:/consul/data 89 | depends_on: 90 | - volume 91 | 92 | logging: 93 | image: edgexfoundry/docker-support-logging-go:1.0.1 94 | ports: 95 | - "48061:48061" 96 | container_name: edgex-support-logging 97 | hostname: edgex-support-logging 98 | networks: 99 | - edgex-network 100 | volumes: 101 | - db-data:/data/db 102 | - log-data:/edgex/logs 103 | - consul-config:/consul/config 104 | - consul-data:/consul/data 105 | depends_on: 106 | - config-seed 107 | - mongo 108 | - volume 109 | 110 | notifications: 111 | image: edgexfoundry/docker-support-notifications-go:1.0.1 112 | ports: 113 | - "48060:48060" 114 | container_name: edgex-support-notifications 115 | hostname: edgex-support-notifications 116 | networks: 117 | - edgex-network 118 | volumes: 119 | - db-data:/data/db 120 | - log-data:/edgex/logs 121 | - consul-config:/consul/config 122 | - consul-data:/consul/data 123 | depends_on: 124 | - logging 125 | 126 | metadata: 127 | image: edgexfoundry/docker-core-metadata-go:1.0.1 128 | ports: 129 | - "48081:48081" 130 | container_name: edgex-core-metadata 131 | hostname: edgex-core-metadata 132 | networks: 133 | - edgex-network 134 | volumes: 135 | - db-data:/data/db 136 | - log-data:/edgex/logs 137 | - consul-config:/consul/config 138 | - consul-data:/consul/data 139 | depends_on: 140 | - logging 141 | 142 | data: 143 | image: edgexfoundry/docker-core-data-go:1.0.1 144 | ports: 145 | - "48080:48080" 146 | - "5563:5563" 147 | container_name: edgex-core-data 148 | hostname: edgex-core-data 149 | networks: 150 | - edgex-network 151 | volumes: 152 | - db-data:/data/db 153 | - log-data:/edgex/logs 154 | - consul-config:/consul/config 155 | - consul-data:/consul/data 156 | depends_on: 157 | - logging 158 | 159 | command: 160 | image: edgexfoundry/docker-core-command-go:1.0.1 161 | ports: 162 | - "48082:48082" 163 | container_name: edgex-core-command 164 | hostname: edgex-core-command 165 | networks: 166 | - edgex-network 167 | volumes: 168 | - db-data:/data/db 169 | - log-data:/edgex/logs 170 | - consul-config:/consul/config 171 | - consul-data:/consul/data 172 | depends_on: 173 | - metadata 174 | 175 | scheduler: 176 | image: edgexfoundry/docker-support-scheduler-go:1.0.1 177 | ports: 178 | - "48085:48085" 179 | container_name: edgex-support-scheduler 180 | hostname: edgex-support-scheduler 181 | networks: 182 | - edgex-network 183 | volumes: 184 | - db-data:/data/db 185 | - log-data:/edgex/logs 186 | - consul-config:/consul/config 187 | - consul-data:/consul/data 188 | depends_on: 189 | - metadata 190 | 191 | export-client: 192 | image: edgexfoundry/docker-export-client-go:1.0.1 193 | ports: 194 | - "48071:48071" 195 | container_name: edgex-export-client 196 | hostname: edgex-export-client 197 | networks: 198 | - edgex-network 199 | volumes: 200 | - db-data:/data/db 201 | - log-data:/edgex/logs 202 | - consul-config:/consul/config 203 | - consul-data:/consul/data 204 | depends_on: 205 | - data 206 | environment: 207 | - EXPORT_CLIENT_MONGO_URL=edgex-mongo 208 | - EXPORT_CLIENT_DISTRO_HOST=export-distro 209 | - EXPORT_CLIENT_CONSUL_HOST=edgex-config-seed 210 | 211 | export-distro: 212 | image: edgexfoundry/docker-export-distro-go:1.0.1 213 | ports: 214 | - "48070:48070" 215 | - "5566:5566" 216 | container_name: edgex-export-distro 217 | hostname: edgex-export-distro 218 | networks: 219 | - edgex-network 220 | volumes: 221 | - db-data:/data/db 222 | - log-data:/edgex/logs 223 | - consul-config:/consul/config 224 | - consul-data:/consul/data 225 | depends_on: 226 | - export-client 227 | environment: 228 | - EXPORT_DISTRO_CLIENT_HOST=export-client 229 | - EXPORT_DISTRO_DATA_HOST=edgex-core-data 230 | - EXPORT_DISTRO_CONSUL_HOST=edgex-config-seed 231 | - EXPORT_DISTRO_MQTTS_CERT_FILE=none 232 | - EXPORT_DISTRO_MQTTS_KEY_FILE=none 233 | 234 | 235 | ################################################################# 236 | # Application Services 237 | ################################################################# 238 | nodered: 239 | image: pomarc/node-red-dashboard 240 | ports: 241 | - 1880:1880 242 | container_name: edgex_nodered 243 | hostname: edgex-nodered 244 | networks: 245 | - edgex-network 246 | 247 | mosquitto: 248 | image: eclipse-mosquitto 249 | ports: 250 | - 1883:1883 251 | container_name: edgex_mqtt_broker 252 | hostname: edgex-mqtt-broker 253 | networks: 254 | - edgex-network 255 | 256 | ################################################################# 257 | # Device Services 258 | ################################################################# 259 | 260 | 261 | ################################################################# 262 | # Tooling 263 | ################################################################# 264 | 265 | portainer: 266 | image: portainer/portainer 267 | ports: 268 | - "9000:9000" 269 | command: -H unix:///var/run/docker.sock 270 | volumes: 271 | - /var/run/docker.sock:/var/run/docker.sock 272 | - portainer_data:/data 273 | depends_on: 274 | - volume 275 | 276 | networks: 277 | edgex-network: 278 | driver: "bridge" 279 | ... 280 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | https://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /examples/MotionDetector/motion_detector_flow.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "9b837477.57dac8", 4 | "type": "tab", 5 | "label": "EdgeX RPi Motion Example", 6 | "disabled": false, 7 | "info": "" 8 | }, 9 | { 10 | "id": "269fde59.27bf32", 11 | "type": "mqtt in", 12 | "z": "9b837477.57dac8", 13 | "name": "Motion State", 14 | "topic": "ExampleRpiMotion", 15 | "qos": "2", 16 | "broker": "4b13cec6.bca34", 17 | "x": 130, 18 | "y": 240, 19 | "wires": [ 20 | [ 21 | "52e8a367.17d2dc" 22 | ] 23 | ] 24 | }, 25 | { 26 | "id": "1c001351.23544d", 27 | "type": "switch", 28 | "z": "9b837477.57dac8", 29 | "name": "IsMotionDetected", 30 | "property": "payload.readings[0].value", 31 | "propertyType": "msg", 32 | "rules": [ 33 | { 34 | "t": "eq", 35 | "v": "1", 36 | "vt": "num" 37 | }, 38 | { 39 | "t": "eq", 40 | "v": "0", 41 | "vt": "str" 42 | } 43 | ], 44 | "checkall": "true", 45 | "outputs": 2, 46 | "x": 570, 47 | "y": 360, 48 | "wires": [ 49 | [ 50 | "372a3cab.424974" 51 | ], 52 | [ 53 | "774c6af2.d15594" 54 | ] 55 | ] 56 | }, 57 | { 58 | "id": "e2cb87b0.c5e458", 59 | "type": "ui_chart", 60 | "z": "9b837477.57dac8", 61 | "name": "Motion Activity", 62 | "group": "9838c993.493de8", 63 | "order": 1, 64 | "width": "12", 65 | "height": "6", 66 | "label": "Motion Activity", 67 | "chartType": "line", 68 | "legend": "false", 69 | "xformat": "HH:mm:ss", 70 | "interpolate": "step", 71 | "nodata": "", 72 | "ymin": "", 73 | "ymax": "", 74 | "removeOlder": 1, 75 | "removeOlderPoints": "", 76 | "removeOlderUnit": "3600", 77 | "cutout": 0, 78 | "colors": [ 79 | "#1f77b4", 80 | "#aec7e8", 81 | "#ff7f0e", 82 | "#2ca02c", 83 | "#98df8a", 84 | "#d62728", 85 | "#ff9896", 86 | "#9467bd", 87 | "#c5b0d5" 88 | ], 89 | "x": 800, 90 | "y": 140, 91 | "wires": [ 92 | [], 93 | [] 94 | ] 95 | }, 96 | { 97 | "id": "31609fc.b8ae76", 98 | "type": "ui_switch", 99 | "z": "9b837477.57dac8", 100 | "name": "Red LED", 101 | "label": "Red LED", 102 | "group": "9838c993.493de8", 103 | "order": 3, 104 | "width": 0, 105 | "height": 0, 106 | "passthru": true, 107 | "decouple": "false", 108 | "topic": "", 109 | "style": "", 110 | "onvalue": "true", 111 | "onvalueType": "bool", 112 | "onicon": "", 113 | "oncolor": "", 114 | "offvalue": "false", 115 | "offvalueType": "bool", 116 | "officon": "", 117 | "offcolor": "", 118 | "x": 320, 119 | "y": 600, 120 | "wires": [ 121 | [ 122 | "5b54b415.f9180c" 123 | ] 124 | ] 125 | }, 126 | { 127 | "id": "52e8a367.17d2dc", 128 | "type": "json", 129 | "z": "9b837477.57dac8", 130 | "name": "", 131 | "pretty": true, 132 | "x": 330, 133 | "y": 240, 134 | "wires": [ 135 | [ 136 | "1c001351.23544d", 137 | "a169436a.1270f" 138 | ] 139 | ] 140 | }, 141 | { 142 | "id": "5b54b415.f9180c", 143 | "type": "switch", 144 | "z": "9b837477.57dac8", 145 | "name": "LED State", 146 | "property": "payload", 147 | "propertyType": "msg", 148 | "rules": [ 149 | { 150 | "t": "true" 151 | }, 152 | { 153 | "t": "false" 154 | } 155 | ], 156 | "checkall": "true", 157 | "outputs": 2, 158 | "x": 530, 159 | "y": 640, 160 | "wires": [ 161 | [ 162 | "2918d654.c8b1ca" 163 | ], 164 | [ 165 | "c14d5143.5133a" 166 | ] 167 | ] 168 | }, 169 | { 170 | "id": "39420062.c2e5b", 171 | "type": "http request", 172 | "z": "9b837477.57dac8", 173 | "name": "Set Green LED", 174 | "method": "PUT", 175 | "ret": "txt", 176 | "url": "http://edgex-core-command:48082/api/v1/device/name/RPiMotionDetector/command/Set_Green_Led", 177 | "tls": "", 178 | "x": 1200, 179 | "y": 400, 180 | "wires": [ 181 | [] 182 | ] 183 | }, 184 | { 185 | "id": "372a3cab.424974", 186 | "type": "function", 187 | "z": "9b837477.57dac8", 188 | "name": "LED On", 189 | "func": "var data = {}\ndata[\"Green_LED\"] = \"true\"\nmsg.payload = JSON.stringify (data);\nreturn msg;", 190 | "outputs": 1, 191 | "noerr": 0, 192 | "x": 980, 193 | "y": 340, 194 | "wires": [ 195 | [ 196 | "39420062.c2e5b", 197 | "62fcce45.d2739" 198 | ] 199 | ] 200 | }, 201 | { 202 | "id": "774c6af2.d15594", 203 | "type": "function", 204 | "z": "9b837477.57dac8", 205 | "name": "LED Off", 206 | "func": "var data = {}\ndata[\"Green_LED\"] = \"false\"\nmsg.payload = JSON.stringify (data);\nreturn msg;", 207 | "outputs": 1, 208 | "noerr": 0, 209 | "x": 980, 210 | "y": 480, 211 | "wires": [ 212 | [ 213 | "39420062.c2e5b", 214 | "62fcce45.d2739" 215 | ] 216 | ] 217 | }, 218 | { 219 | "id": "62fcce45.d2739", 220 | "type": "debug", 221 | "z": "9b837477.57dac8", 222 | "name": "", 223 | "active": true, 224 | "console": "false", 225 | "complete": "false", 226 | "x": 1190, 227 | "y": 520, 228 | "wires": [] 229 | }, 230 | { 231 | "id": "a169436a.1270f", 232 | "type": "function", 233 | "z": "9b837477.57dac8", 234 | "name": "Motion Data", 235 | "func": "msg.payload = msg.payload.readings[0].value;\nreturn msg;", 236 | "outputs": 1, 237 | "noerr": 0, 238 | "x": 550, 239 | "y": 160, 240 | "wires": [ 241 | [ 242 | "e2cb87b0.c5e458", 243 | "8aedc0c5.e57a2" 244 | ] 245 | ] 246 | }, 247 | { 248 | "id": "c1ad6204.af703", 249 | "type": "http request", 250 | "z": "9b837477.57dac8", 251 | "name": "Set Red LED", 252 | "method": "PUT", 253 | "ret": "txt", 254 | "url": "http://edgex-core-command:48082/api/v1/device/name/RPiMotionDetector/command/Set_Red_Led", 255 | "tls": "", 256 | "x": 990, 257 | "y": 760, 258 | "wires": [ 259 | [] 260 | ] 261 | }, 262 | { 263 | "id": "c14d5143.5133a", 264 | "type": "function", 265 | "z": "9b837477.57dac8", 266 | "name": "LED Off", 267 | "func": "var data = {}\ndata[\"Red_LED\"] = \"false\"\nmsg.payload = JSON.stringify (data);\nreturn msg;", 268 | "outputs": 1, 269 | "noerr": 0, 270 | "x": 760, 271 | "y": 800, 272 | "wires": [ 273 | [ 274 | "c1ad6204.af703" 275 | ] 276 | ] 277 | }, 278 | { 279 | "id": "2918d654.c8b1ca", 280 | "type": "function", 281 | "z": "9b837477.57dac8", 282 | "name": "LED On", 283 | "func": "var data = {}\ndata[\"Red_LED\"] = \"true\"\nmsg.payload = JSON.stringify (data);\nreturn msg;", 284 | "outputs": 1, 285 | "noerr": 0, 286 | "x": 780, 287 | "y": 680, 288 | "wires": [ 289 | [ 290 | "c1ad6204.af703" 291 | ] 292 | ] 293 | }, 294 | { 295 | "id": "8aedc0c5.e57a2", 296 | "type": "debug", 297 | "z": "9b837477.57dac8", 298 | "name": "", 299 | "active": false, 300 | "console": "false", 301 | "complete": "true", 302 | "x": 750, 303 | "y": 220, 304 | "wires": [] 305 | }, 306 | { 307 | "id": "8b3bba52.12be78", 308 | "type": "ui_button", 309 | "z": "9b837477.57dac8", 310 | "name": "ClearGraph", 311 | "group": "9838c993.493de8", 312 | "order": 2, 313 | "width": "3", 314 | "height": "1", 315 | "passthru": false, 316 | "label": "Clear Graph", 317 | "color": "", 318 | "bgcolor": "", 319 | "icon": "", 320 | "payload": "[]", 321 | "payloadType": "json", 322 | "topic": "", 323 | "x": 430, 324 | "y": 60, 325 | "wires": [ 326 | [ 327 | "e2cb87b0.c5e458" 328 | ] 329 | ] 330 | }, 331 | { 332 | "id": "5c9f14bb.363eac", 333 | "type": "inject", 334 | "z": "9b837477.57dac8", 335 | "name": "", 336 | "topic": "", 337 | "payload": "false", 338 | "payloadType": "bool", 339 | "repeat": "", 340 | "crontab": "", 341 | "once": true, 342 | "x": 110, 343 | "y": 580, 344 | "wires": [ 345 | [ 346 | "31609fc.b8ae76" 347 | ] 348 | ] 349 | }, 350 | { 351 | "id": "4b13cec6.bca34", 352 | "type": "mqtt-broker", 353 | "z": "", 354 | "broker": "edgex_mqtt_broker", 355 | "port": "1883", 356 | "tls": "92803d3a.e24e8", 357 | "clientid": "", 358 | "usetls": false, 359 | "compatmode": true, 360 | "keepalive": "60", 361 | "cleansession": true, 362 | "willTopic": "", 363 | "willQos": "0", 364 | "willPayload": "", 365 | "birthTopic": "", 366 | "birthQos": "0", 367 | "birthPayload": "" 368 | }, 369 | { 370 | "id": "9838c993.493de8", 371 | "type": "ui_group", 372 | "z": "", 373 | "name": "Motion Detector Example", 374 | "tab": "97829435.202208", 375 | "order": 1, 376 | "disp": true, 377 | "width": "12" 378 | }, 379 | { 380 | "id": "92803d3a.e24e8", 381 | "type": "tls-config", 382 | "z": "", 383 | "name": "", 384 | "cert": "", 385 | "key": "", 386 | "ca": "", 387 | "certname": "", 388 | "keyname": "", 389 | "caname": "", 390 | "verifyservercert": true 391 | }, 392 | { 393 | "id": "97829435.202208", 394 | "type": "ui_tab", 395 | "z": "", 396 | "name": "EdgeX Device RPi Examples", 397 | "icon": "dashboard", 398 | "order": 1 399 | } 400 | ] 401 | -------------------------------------------------------------------------------- /src/c/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 3 | * IoTech Ltd 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | * 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "device_rpi.h" 14 | 15 | static bool stop = false; 16 | 17 | static void rpi_inthandler (int i) 18 | { 19 | stop = true; 20 | } 21 | 22 | static rpi_attributes_t *get_rpiattributes (const edgex_nvpairs *device_attr) 23 | { 24 | rpi_attributes_t *rpi_attr = (rpi_attributes_t *) malloc (sizeof (rpi_attributes_t)); 25 | for (; device_attr != NULL; device_attr = device_attr->next) 26 | { 27 | if (strcmp (device_attr->name, "Pin_Num") == 0) 28 | { 29 | rpi_attr->pin_no = device_attr->value; 30 | } 31 | else if (strcmp (device_attr->name, "Interface") == 0) 32 | { 33 | rpi_attr->pin_type = device_attr->value; 34 | } 35 | else if (strcmp (device_attr->name, "Type") == 0) 36 | { 37 | rpi_attr->type = device_attr->value; 38 | } 39 | else if (strcmp (device_attr->name, "normalize") == 0) 40 | { 41 | rpi_attr->normalize = (strcasecmp (device_attr->value, "true") == 0); 42 | } 43 | } 44 | return rpi_attr; 45 | } 46 | 47 | static rpi_dev_ctxt_t * rpi_device_lookup (rpi_pidriver_t *impln, char *pin) 48 | { 49 | for (int index = 0; index < RPI_NO_PORTS; index++) 50 | { 51 | if (impln->dev[index] != NULL) 52 | { 53 | if (strcmp (impln->dev[index]->pin_number, pin) == 0) 54 | { 55 | return impln->dev[index]; 56 | } 57 | } 58 | else 59 | { 60 | break; 61 | } 62 | } 63 | return NULL; 64 | } 65 | 66 | static rpi_dev_ctxt_t *rpi_set_devctxt 67 | (rpi_pidriver_t *impln, void *dev, char *pin, rpi_interface_type_t interface_type) 68 | { 69 | int index = 0; 70 | rpi_dev_ctxt_t *mraa_dev = NULL; 71 | 72 | for (; index < RPI_NO_PORTS; index++) 73 | { 74 | if (impln->dev[index] == NULL) 75 | { 76 | mraa_dev = malloc (sizeof (rpi_dev_ctxt_t)); 77 | if (strstr (pin, "I2C")) 78 | { 79 | rpi_i2c_dev_ctxt_t *i2c_dev = malloc (sizeof (rpi_i2c_dev_ctxt_t)); 80 | i2c_dev->dev = dev; 81 | mraa_dev->dev_ctxt = (void *) i2c_dev; 82 | } 83 | else 84 | { 85 | mraa_dev->dev_ctxt = dev; 86 | } 87 | mraa_dev->pin_number = malloc (strlen (pin)); 88 | strcpy (mraa_dev->pin_number, pin); 89 | mraa_dev->pin_type = interface_type; 90 | 91 | impln->dev[index] = mraa_dev; 92 | break; 93 | } 94 | } 95 | return mraa_dev; 96 | } 97 | 98 | static mraa_result_t rpi_gpio_init (rpi_pidriver_t *impln, char *pin, char *type) 99 | { 100 | mraa_result_t status = MRAA_SUCCESS; 101 | rpi_interface_type_t pin_type = RPI_GPIO; 102 | 103 | int pin_number = atoi(pin); 104 | iot_log_error(impln->lc, "Initializing pin %d", pin_number); 105 | mraa_gpio_context dev = mraa_gpio_init (pin_number); 106 | if (dev == NULL) 107 | { 108 | status = MRAA_ERROR_UNSPECIFIED; 109 | iot_log_error (impln->lc, "Failed to initialize a device at GPIO %s", pin); 110 | } 111 | else 112 | { 113 | if (strcmp (type, "OUT") == 0) 114 | { 115 | status = mraa_gpio_dir (dev, MRAA_GPIO_OUT); 116 | } 117 | else if (strcmp (type, "IN") == 0) 118 | { 119 | status = mraa_gpio_dir (dev, MRAA_GPIO_IN); 120 | } 121 | else 122 | { 123 | /* IN/OUT Configuration not supported - ignore */ 124 | } 125 | } 126 | 127 | if (status != MRAA_SUCCESS) 128 | { 129 | iot_log_error (impln->lc, "Failed to set the GPIO %s to %s mode", pin, type); 130 | } 131 | else 132 | { 133 | if ((rpi_set_devctxt (impln, (void *) dev, pin, pin_type)) == NULL) 134 | { 135 | iot_log_error (impln->lc, "Unable to set the mraadev_ctxt at %s", pin, type); 136 | status = MRAA_ERROR_UNSPECIFIED; 137 | } 138 | } 139 | return status; 140 | } 141 | 142 | static bool rpi_init (void *impl, struct iot_logger_t *lc, const edgex_nvpairs *config) 143 | { 144 | mraa_result_t status = MRAA_SUCCESS; 145 | rpi_pidriver_t *impln = (rpi_pidriver_t *) impl; 146 | impln->lc = lc; 147 | pthread_mutex_init (&impln->mutex, NULL); 148 | 149 | iot_log_debug (lc, "driver initialization"); 150 | { 151 | edgex_deviceprofile *profiles = NULL; 152 | 153 | status = mraa_init (); 154 | if (status != MRAA_SUCCESS) 155 | { 156 | iot_log_error (lc, "RaspberryPi driver initialization failed"); 157 | return false; 158 | } 159 | 160 | //mraa_add_subplatform (MRAA_RPIPI, "0"); 161 | 162 | /* read the attributes from the device profile to initialize the driver */ 163 | profiles = edgex_device_profiles (impln->svc); 164 | 165 | while (profiles) 166 | { 167 | edgex_deviceresource *dev_obj = profiles->device_resources; 168 | rpi_attributes_t *rpi_attr = NULL; 169 | for (; dev_obj != NULL; dev_obj = dev_obj->next) 170 | { 171 | edgex_nvpairs *dev_attr = dev_obj->attributes; 172 | assert (dev_attr != NULL); 173 | 174 | rpi_attr = get_rpiattributes (dev_attr); 175 | 176 | rpi_dev_ctxt_t *dev = rpi_device_lookup (impln, rpi_attr->pin_no); 177 | if (dev != NULL) 178 | { 179 | /* device is initialized */ 180 | continue; 181 | } 182 | else 183 | { 184 | if (strcmp (rpi_attr->pin_type, "GPIO") == 0) 185 | { 186 | status = rpi_gpio_init (impln, rpi_attr->pin_no, rpi_attr->type); 187 | assert (!status); 188 | } 189 | else 190 | { 191 | /* PWM & Serial interface support not implemented */ 192 | status = MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; 193 | } 194 | } 195 | free (rpi_attr); 196 | } 197 | profiles = profiles->next; 198 | } 199 | free (profiles); 200 | } 201 | 202 | return (status == MRAA_SUCCESS); 203 | } 204 | 205 | static bool rpi_gethandler 206 | ( 207 | void *impl, 208 | const char *devname, 209 | const edgex_protocols *protocols, 210 | uint32_t nreadings, 211 | const edgex_device_commandrequest *requests, 212 | edgex_device_commandresult *readings 213 | ) 214 | { 215 | rpi_pidriver_t *impln = (rpi_pidriver_t *) impl; 216 | 217 | pthread_mutex_lock (&impln->mutex); 218 | const edgex_nvpairs *dev_attr = requests->attributes; 219 | assert (dev_attr != NULL); 220 | rpi_attributes_t *rpi_attr = get_rpiattributes (dev_attr); 221 | bool ret_status = true; 222 | 223 | rpi_dev_ctxt_t *mraa_devctxt = rpi_device_lookup (impln, rpi_attr->pin_no); 224 | if (mraa_devctxt != NULL) 225 | { 226 | volatile int read_value; 227 | if (strcmp (rpi_attr->pin_type, "GPIO") == 0) 228 | { 229 | mraa_gpio_context gpio_dev = (mraa_gpio_context) mraa_devctxt->dev_ctxt; 230 | read_value = mraa_gpio_read (gpio_dev); 231 | 232 | assert (nresults == 1); 233 | 234 | if (read_value == -1) 235 | { 236 | /* error */ 237 | ret_status = false; 238 | } 239 | /* RaspberryPi Button */ 240 | else if (requests->type == Uint8) 241 | { 242 | readings->value.ui8_result = (uint8_t) read_value; 243 | readings->type = Uint8; 244 | } 245 | else 246 | { 247 | /* No other type support available for GPIO in the profile */ 248 | ret_status = false; 249 | } 250 | } /* GPIO */ 251 | else 252 | { 253 | /* Only GPIO types are supported */ 254 | ret_status = false; 255 | } 256 | } /* dev_ctxt != NULL */ 257 | free (rpi_attr); 258 | pthread_mutex_unlock (&impln->mutex); 259 | return ret_status; 260 | } 261 | 262 | static bool rpi_puthandler 263 | ( 264 | void *impl, 265 | const char *devname, 266 | const edgex_protocols *protocols, 267 | uint32_t nvalues, 268 | const edgex_device_commandrequest *requests, 269 | const edgex_device_commandresult *readings 270 | ) 271 | { 272 | mraa_result_t status = MRAA_SUCCESS; 273 | rpi_pidriver_t *impln = (rpi_pidriver_t *) impl; 274 | 275 | pthread_mutex_lock (&impln->mutex); 276 | /* Get the device context */ 277 | const edgex_nvpairs *dev_attr = requests->attributes; 278 | assert (dev_attr != NULL); 279 | rpi_attributes_t *rpi_attr = get_rpiattributes (dev_attr); 280 | 281 | rpi_dev_ctxt_t *mraa_devctxt = rpi_device_lookup (impln, rpi_attr->pin_no); 282 | if (mraa_devctxt != NULL) 283 | { 284 | if (strcmp (rpi_attr->pin_type, "GPIO") == 0) 285 | { 286 | mraa_gpio_context gpio_dev = (mraa_gpio_context) mraa_devctxt->dev_ctxt; 287 | 288 | assert (!requests->type == Bool); 289 | assert (nvalues == 1); 290 | 291 | status = mraa_gpio_write (gpio_dev, readings[--nvalues].value.bool_result); 292 | } 293 | else 294 | { 295 | /* PWM & Serial interface support not implemented */ 296 | status = MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; 297 | } 298 | } 299 | free (rpi_attr); 300 | pthread_mutex_unlock (&impln->mutex); 301 | return (status == MRAA_SUCCESS); 302 | } 303 | 304 | static bool rpi_disconnect (void *impl, edgex_protocols *device) 305 | { 306 | free (impl); 307 | return true; 308 | } 309 | 310 | static void rpi_stop (void *impl, bool force) 311 | { 312 | rpi_pidriver_t *impln = (rpi_pidriver_t *) impl; 313 | mraa_result_t status = MRAA_SUCCESS; 314 | 315 | iot_log_debug (impln->lc, "rpi stop call"); 316 | 317 | /* Release the resources */ 318 | for (int index = 0; index < RPI_NO_PORTS; index++) 319 | { 320 | if (impln->dev[index] != NULL) 321 | { 322 | switch (impln->dev[index]->pin_type) 323 | { 324 | case RPI_GPIO: 325 | { 326 | mraa_gpio_context gpio_dev = (mraa_gpio_context) impln->dev[index]->dev_ctxt; 327 | status |= mraa_gpio_close (gpio_dev); 328 | break; 329 | } 330 | default: 331 | { 332 | status |= MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; 333 | iot_log_error (impln->lc, "rpi_stop(), interface type %d not implemented", impln->dev[index]->pin_type); 334 | break; 335 | } 336 | } 337 | free (impln->dev[index]->pin_number); 338 | free (impln->dev[index]); 339 | impln->dev[index] = NULL; 340 | 341 | } /* dev != NULL */ 342 | } 343 | 344 | if (status != MRAA_SUCCESS) 345 | { 346 | iot_log_error (impln->lc, "rpi_stop() failure"); 347 | } 348 | mraa_deinit (); 349 | pthread_mutex_destroy (&impln->mutex); 350 | } 351 | 352 | static void usage (void) 353 | { 354 | printf ("Options: \n"); 355 | printf (" -h, --help : Show this text\n"); 356 | printf (" -n, --name= : Set the device service name\n"); 357 | printf (" -r, --registry= : Use the registry service\n"); 358 | printf (" -p, --profile= : Set the profile name\n"); 359 | printf (" -c, --confdir= : Set the configuration directory\n"); 360 | } 361 | 362 | static bool testArg (int argc, char *argv[], int *pos, const char *pshort, const char *plong, char **var) 363 | { 364 | if (strcmp (argv[*pos], pshort) == 0 || strcmp (argv[*pos], plong) == 0) 365 | { 366 | if (*pos < argc - 1) 367 | { 368 | (*pos)++; 369 | *var = argv[*pos]; 370 | (*pos)++; 371 | return true; 372 | } 373 | else 374 | { 375 | printf ("Option %s requires an argument\n", argv[*pos]); 376 | exit (0); 377 | } 378 | } 379 | char *eq = strchr (argv[*pos], '='); 380 | if (eq) 381 | { 382 | if (strncmp (argv[*pos], pshort, eq - argv[*pos]) == 0 || strncmp (argv[*pos], plong, eq - argv[*pos]) == 0) 383 | { 384 | if (strlen (++eq)) 385 | { 386 | *var = eq; 387 | (*pos)++; 388 | return true; 389 | } 390 | else 391 | { 392 | printf ("Option %s requires an argument\n", argv[*pos]); 393 | exit (0); 394 | } 395 | } 396 | } 397 | return false; 398 | } 399 | 400 | int main (int argc, char *argv[]) 401 | { 402 | char *profile = ""; 403 | char *confdir = ""; 404 | char *svcname = "device-rpi"; 405 | char *regURL = getenv ("EDGEX_REGISTRY"); 406 | edgex_error err; 407 | 408 | rpi_pidriver_t * implObject = malloc (sizeof (rpi_pidriver_t)); 409 | memset (implObject, 0, sizeof (rpi_pidriver_t)); 410 | 411 | int n = 1; 412 | while (n < argc) 413 | { 414 | if (strcmp (argv[n], "-h") == 0 || strcmp (argv[n], "--help") == 0) 415 | { 416 | usage (); 417 | return 0; 418 | } 419 | if (testArg (argc, argv, &n, "-r", "--registry", ®URL)) 420 | { 421 | continue; 422 | } 423 | if (testArg (argc, argv, &n, "-n", "--name", &svcname)) 424 | { 425 | continue; 426 | } 427 | if (testArg (argc, argv, &n, "-p", "--profile", &profile)) 428 | { 429 | continue; 430 | } 431 | if (testArg (argc, argv, &n, "-c", "--confdir", &confdir)) 432 | { 433 | continue; 434 | } 435 | 436 | printf ("Unknown option %s\n", argv[n]); 437 | usage (); 438 | return 0; 439 | } 440 | 441 | err.code = 0; 442 | 443 | edgex_device_callbacks myImpls = 444 | { 445 | rpi_init, 446 | NULL, 447 | rpi_gethandler, 448 | rpi_puthandler, 449 | rpi_disconnect, 450 | rpi_stop 451 | }; 452 | 453 | edgex_device_service *rpi_service = edgex_device_service_new (RPI_SVC, "1.0", implObject, myImpls, &err); 454 | RPI_ERR_CHECK (err); 455 | 456 | implObject->svc = rpi_service; 457 | edgex_device_service_start (rpi_service, regURL, profile, confdir, &err); 458 | RPI_ERR_CHECK (err); 459 | 460 | printf ("\nRunning - press ctrl-c to exit\n"); 461 | signal (SIGTERM, rpi_inthandler); 462 | signal (SIGINT, rpi_inthandler); 463 | 464 | while (!stop) 465 | { 466 | sleep (1); 467 | } 468 | 469 | edgex_error e; 470 | e.code = 0; 471 | edgex_device_service_stop (rpi_service, true, &e); 472 | RPI_ERR_CHECK (e); 473 | 474 | free (implObject); 475 | return 0; 476 | } 477 | --------------------------------------------------------------------------------