├── examples
├── complex
│ └── esp32
│ │ ├── camera
│ │ ├── .gitignore
│ │ ├── base64.h
│ │ ├── README.md
│ │ ├── esp32-mqtt.h
│ │ ├── ciotc_config.h
│ │ └── camera.ino
│ │ ├── ios-gateway
│ │ ├── extras
│ │ │ ├── iOS_IoTCore_Client_Demo
│ │ │ │ ├── Assets.xcassets
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ ├── IoTCore.imageset
│ │ │ │ │ │ ├── Cloud IoT Core.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── Button.colorset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── Background.colorset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── DarkShadow.colorset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── LightShadow.colorset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── textcolor.colorset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── AppIcon.appiconset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ ├── Base.lproj
│ │ │ │ │ ├── LaunchScreen.storyboard
│ │ │ │ │ └── Main.storyboard
│ │ │ │ ├── LottieView.swift
│ │ │ │ ├── AppDelegate.swift
│ │ │ │ ├── Info.plist
│ │ │ │ ├── SceneDelegate.swift
│ │ │ │ ├── Animations
│ │ │ │ │ └── 3973-ripples.json
│ │ │ │ ├── SwiftUIClient.swift
│ │ │ │ └── IoTBLEClient.swift
│ │ │ ├── iOS_IoTCore_Client.xcodeproj
│ │ │ │ ├── .gitignore
│ │ │ │ ├── project.xcworkspace
│ │ │ │ │ ├── contents.xcworkspacedata
│ │ │ │ │ └── xcshareddata
│ │ │ │ │ │ └── IDEWorkspaceChecks.plist
│ │ │ │ └── xcshareddata
│ │ │ │ │ └── xcschemes
│ │ │ │ │ └── iOS_IoTCore_Client.xcscheme
│ │ │ └── Podfile
│ │ └── ios-gateway.ino
│ │ └── Gateway
│ │ ├── Esp32-gateway
│ │ ├── Esp32-gateway.ino
│ │ ├── connect-serial.h
│ │ ├── ciotc_config.h
│ │ └── esp32-mqtt.h
│ │ ├── README.md
│ │ └── Esp32-delegate
│ │ └── Esp32-delegate.ino
├── Esp8266-lwmqtt
│ ├── data
│ │ ├── GSR4.crt
│ │ └── gtsltsr.crt
│ ├── Esp8266-lwmqtt.ino
│ ├── ciotc_config.h
│ └── esp8266_mqtt.h
├── universal-lwmqtt
│ ├── universal-lwmqtt.ino
│ ├── ciotc_config.h
│ └── universal-mqtt.h
├── MKR1000-lwmqtt
│ ├── MKR1000-lwmqtt.ino
│ ├── ciotc_config.h
│ └── mkr1000-mqtt.h
└── Esp32-lwmqtt
│ ├── Esp32-lwmqtt.ino
│ ├── ciotc_config.h
│ └── esp32-mqtt.h
├── .gitignore
├── pio
├── .gitignore
├── Esp32-mqtt
│ └── platformio.ini
├── Esp32-ssd1306
│ └── platformio.ini
├── Esp8266-http
│ └── platformio.ini
└── Basic-MKR1000
│ └── platformio.ini
├── library.properties
├── library_check.sh
├── .travis.yml
├── src
├── crypto
│ ├── prng.h
│ ├── prng.cpp
│ ├── sha256.h
│ ├── ecdsa.h
│ ├── ecc.h
│ ├── sha256.cpp
│ └── ecdsa.cpp
├── jwt.h
├── CloudIoTCore.h
├── CloudIoTCoreMqtt.h
├── CloudIoTCoreDevice.h
├── jwt.cpp
└── CloudIoTCoreDevice.cpp
├── CONTRIBUTING.md
├── pull_crypto.sh
└── README.md
/examples/complex/esp32/camera/.gitignore:
--------------------------------------------------------------------------------
1 | ciotc_config.h
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | */*/ciotc_config.h
2 | .vscode
3 | build
4 | .DS_Store
--------------------------------------------------------------------------------
/pio/.gitignore:
--------------------------------------------------------------------------------
1 | */.pioenvs/
2 | */.piolibdeps/
3 | .sconsign.dblite
4 |
--------------------------------------------------------------------------------
/examples/Esp8266-lwmqtt/data/GSR4.crt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/google-cloud-iot-arduino/HEAD/examples/Esp8266-lwmqtt/data/GSR4.crt
--------------------------------------------------------------------------------
/examples/Esp8266-lwmqtt/data/gtsltsr.crt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/google-cloud-iot-arduino/HEAD/examples/Esp8266-lwmqtt/data/gtsltsr.crt
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client.xcodeproj/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | ## Build generated
3 | build/
4 | DerivedData/
5 | ## Various settings
6 | *.pbxuser
7 | xcuserdata/
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Assets.xcassets/IoTCore.imageset/Cloud IoT Core.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/google-cloud-iot-arduino/HEAD/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Assets.xcassets/IoTCore.imageset/Cloud IoT Core.png
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'iOS_IoTCore_Client' do
5 | pod 'SwiftJWT'
6 | use_frameworks! # Add this if you are targeting iOS 8+ or using Swift
7 | pod 'CocoaMQTT'
8 | end
9 |
10 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Assets.xcassets/IoTCore.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Cloud IoT Core.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Assets.xcassets/Button.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.859",
9 | "green" : "0.447",
10 | "red" : "0.259"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | name=Google Cloud IoT Core JWT
2 | version=1.1.11
3 | author=Vladimir Korukov
4 | maintainer=Gus Class
5 | sentence=Demonstrates JWT generation for connecting Arduino clients to Google Cloud IoT Core.
6 | paragraph=Experimental library for trying out Google Cloud IoT Core. Note that the library is not intended for production use and has no associated SLO/SLA or support from Google.
7 | category=Communication
8 | url=https://cloud.google.com/iot/docs
9 | architectures=*
10 | includes=jwt.h
11 |
--------------------------------------------------------------------------------
/library_check.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright 2020 Google LLC
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | # empty for now, add QA checkin' later!
17 |
--------------------------------------------------------------------------------
/pio/Esp32-mqtt/platformio.ini:
--------------------------------------------------------------------------------
1 | ; PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter, extra scripting
4 | ; Upload options: custom port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ;
7 | ; Please visit documentation for the other options and examples
8 | ; http://docs.platformio.org/page/projectconf.html
9 |
10 | [env:esp32dev]
11 | platform = espressif32
12 | framework = arduino
13 | board = esp32dev
14 |
15 | [env:esp-wrover-kit]
16 | platform = espressif32
17 | framework = arduino
18 | board = esp-wrover-kit
19 |
20 | [env:quantum]
21 | platform = espressif32
22 | framework = arduino
23 | board = quantum
24 |
25 | [env:lolin32]
26 | platform = espressif32
27 | framework = arduino
28 | board = lolin32
29 |
--------------------------------------------------------------------------------
/pio/Esp32-ssd1306/platformio.ini:
--------------------------------------------------------------------------------
1 | ; PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter, extra scripting
4 | ; Upload options: custom port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ;
7 | ; Please visit documentation for the other options and examples
8 | ; http://docs.platformio.org/page/projectconf.html
9 |
10 | [env:esp32dev]
11 | platform = espressif32
12 | framework = arduino
13 | board = esp32dev
14 |
15 | [env:esp-wrover-kit]
16 | platform = espressif32
17 | framework = arduino
18 | board = esp-wrover-kit
19 |
20 | [env:quantum]
21 | platform = espressif32
22 | framework = arduino
23 | board = quantum
24 |
25 | [env:lolin32]
26 | platform = espressif32
27 | framework = arduino
28 | board = lolin32
29 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 | sudo: false
3 | cache:
4 | directories:
5 | - ~/arduino_ide
6 | - ~/.arduino15/packages/
7 | git:
8 | depth: false
9 | quiet: true
10 | addons:
11 | apt:
12 | sources:
13 | - llvm-toolchain-trusty-5.0
14 | - key_url: 'http://apt.llvm.org/llvm-snapshot.gpg.key'
15 | packages:
16 | - python3-pip
17 | - python3-wheel
18 | - clang-format-5.0
19 | env:
20 | global:
21 | - ARDUINO_IDE_VERSION="1.8.13"
22 | - PRETTYNAME="Google Cloud IoT Arduino Library"
23 | # Optional, will default to "$TRAVIS_BUILD_DIR/Doxyfile"
24 | # - DOXYFILE: $TRAVIS_BUILD_DIR/Doxyfile
25 |
26 | before_install:
27 | - source $TRAVIS_BUILD_DIR/install.sh
28 |
29 | install:
30 | - arduino --install-library "MQTT","WiFi101","DHT sensor library","Adafruit Unified Sensor"
31 | script:
32 | - build_main_platforms
33 |
34 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Assets.xcassets/Background.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.965",
9 | "green" : "0.918",
10 | "red" : "0.871"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "0.118",
27 | "green" : "0.114",
28 | "red" : "0.102"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Assets.xcassets/DarkShadow.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.847",
9 | "green" : "0.796",
10 | "red" : "0.745"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "0.094",
27 | "green" : "0.082",
28 | "red" : "0.082"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Assets.xcassets/LightShadow.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "1.000",
9 | "green" : "0.976",
10 | "red" : "0.953"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "0.161",
27 | "green" : "0.145",
28 | "red" : "0.141"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Assets.xcassets/textcolor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.161",
9 | "green" : "0.145",
10 | "red" : "0.141"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "0.976",
28 | "red" : "0.953"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/crypto/prng.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 |
16 | #ifndef _PRNG_H_
17 | #define _PRNG_H_
18 |
19 | #include
20 |
21 | // Fills buf with random chars.
22 | int prng(unsigned char *buf, size_t len);
23 |
24 | #endif /* _PRNG_H_ */
25 |
--------------------------------------------------------------------------------
/src/crypto/prng.cpp:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 |
16 | #include "prng.h"
17 |
18 | #if defined(ESP8266)
19 | #include "esp8266_peri.h" // Can use RANDOM_REG32
20 | #endif
21 |
22 | int prng(unsigned char *buf, size_t len) {
23 | while (len--) {
24 | #if defined(ESP8266)
25 | *buf++ = RANDOM_REG32 % 255;
26 | break;
27 | #endif
28 | *buf++ = random(0, 255);
29 | }
30 | return 1;
31 | }
32 |
--------------------------------------------------------------------------------
/src/jwt.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 |
16 | #ifndef JWT_H_
17 | #define JWT_H_
18 |
19 | #include
20 | #include "crypto/nn.h"
21 |
22 | String CreateJwt(String &project_id, long long int time, NN_DIGIT *priv_key);
23 | String CreateJwt(String &project_id, long long int time, NN_DIGIT *priv_key, int jwt_exp_secs);
24 | String CreateJwt(const char *project_id, long long int time, NN_DIGIT *priv_key, int jwt_exp_secs);
25 |
26 | #endif // JWT_H_
27 |
--------------------------------------------------------------------------------
/src/crypto/sha256.h:
--------------------------------------------------------------------------------
1 | // AUTOGENERATED, DO NOT EDIT. See CONTRIBUTING.md for instructions.
2 | /*********************************************************************
3 | * Filename: sha256.h
4 | * Author: Brad Conte (brad AT bradconte.com)
5 | * Copyright:
6 | * Disclaimer: This code is presented "as is" without any guarantees.
7 | * Details: Defines the API for the corresponding SHA1 implementation.
8 | *********************************************************************/
9 |
10 | #ifndef SHA256_H
11 | #define SHA256_H
12 |
13 | /*************************** HEADER FILES ***************************/
14 | #include
15 | #include
16 |
17 | /****************************** MACROS ******************************/
18 | #define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
19 |
20 | /**************************** DATA TYPES ****************************/
21 | typedef unsigned char BYTE; // 8-bit byte
22 | typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
23 |
24 | class Sha256 {
25 | public:
26 | Sha256();
27 | void update(const BYTE data[], size_t len);
28 | void final(BYTE hash[]);
29 | private:
30 | BYTE data[64];
31 | WORD datalen;
32 | unsigned long long bitlen;
33 | WORD state[8];
34 | void transform();
35 | };
36 |
37 | #endif // SHA256_H
38 |
--------------------------------------------------------------------------------
/pio/Esp8266-http/platformio.ini:
--------------------------------------------------------------------------------
1 | ; PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter, extra scripting
4 | ; Upload options: custom port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ;
7 | ; Please visit documentation for the other options and examples
8 | ; http://docs.platformio.org/page/projectconf.html
9 |
10 | [env:d1]
11 | platform = espressif8266
12 | framework = arduino
13 | board = d1
14 |
15 | [env:d1_mini]
16 | platform = espressif8266
17 | framework = arduino
18 | board = d1_mini
19 |
20 | [env:espduino]
21 | platform = espressif8266
22 | framework = arduino
23 | board = espduino
24 |
25 | [env:espino]
26 | platform = espressif8266
27 | framework = arduino
28 | board = espino
29 |
30 | [env:espinotee]
31 | platform = espressif8266
32 | framework = arduino
33 | board = espinotee
34 |
35 | [env:espresso_lite_v1]
36 | platform = espressif8266
37 | framework = arduino
38 | board = espresso_lite_v1
39 |
40 | [env:espresso_lite_v2]
41 | platform = espressif8266
42 | framework = arduino
43 | board = espresso_lite_v2
44 |
45 | [env:esp01]
46 | platform = espressif8266
47 | framework = arduino
48 | board = esp01
49 |
50 | [env:nodemcuv2]
51 | platform = espressif8266
52 | framework = arduino
53 | board = nodemcuv2
54 |
55 | [env:thing]
56 | platform = espressif8266
57 | framework = arduino
58 | board = thing
59 |
--------------------------------------------------------------------------------
/src/CloudIoTCore.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 |
16 | #ifndef CloudIoTCore_h
17 | #define CloudIoTCore_h
18 |
19 | #include "CloudIoTCoreDevice.h"
20 |
21 | #ifndef CLOUD_IOT_CORE_HTTP_HOST
22 | #define CLOUD_IOT_CORE_HTTP_HOST "cloudiotdevice.googleapis.com"
23 | #endif
24 |
25 | #ifndef CLOUD_IOT_CORE_HTTP_PORT
26 | #define CLOUD_IOT_CORE_HTTP_PORT 443
27 | #endif
28 |
29 | #ifndef CLOUD_IOT_CORE_MQTT_HOST
30 | #define CLOUD_IOT_CORE_MQTT_HOST "mqtt.googleapis.com"
31 | #endif
32 |
33 | #ifndef CLOUD_IOT_CORE_MQTT_HOST_LTS
34 | #define CLOUD_IOT_CORE_MQTT_HOST_LTS "mqtt.2030.ltsapis.goog"
35 | #endif
36 |
37 | #ifndef CLOUD_IOT_CORE_MQTT_PORT
38 | #define CLOUD_IOT_CORE_MQTT_PORT 8883
39 | #endif
40 |
41 | #endif // CloudIoTCore_h
42 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Editing files in src/crypto
7 |
8 | The files in src/crypto are pulled from external git repositories. They are not
9 | submoduled so that this repo can be exported as an Arduino library. If you want
10 | to modify prng.*, modify it directly in this repo. If you want to modify other
11 | file either modify them using pull_crypto.sh, or modify them in the repos they
12 | are pulled from.
13 |
14 | ## Contributor License Agreement
15 |
16 | Contributions to this project must be accompanied by a Contributor License
17 | Agreement. You (or your employer) retain the copyright to your contribution;
18 | this simply gives us permission to use and redistribute your contributions as
19 | part of the project. Head over to to see
20 | your current agreements on file or to sign a new one.
21 |
22 | You generally only need to submit a CLA once, so if you've already submitted one
23 | (even if it was for a different project), you probably don't need to do it
24 | again.
25 |
26 | ## Code reviews
27 |
28 | All submissions, including submissions by project members, require review. We
29 | use GitHub pull requests for this purpose. Consult
30 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
31 | information on using pull requests.
32 |
33 | ## Community Guidelines
34 |
35 | This project follows [Google's Open Source Community
36 | Guidelines](https://opensource.google.com/conduct/).
37 |
--------------------------------------------------------------------------------
/pio/Basic-MKR1000/platformio.ini:
--------------------------------------------------------------------------------
1 | ; PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter, extra scripting
4 | ; Upload options: custom port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ;
7 | ; Please visit documentation for the other options and examples
8 | ; http://docs.platformio.org/page/projectconf.html
9 |
10 | ; no SPI
11 | [env:adafruit_feather_m0]
12 | platform = atmelsam
13 | framework = arduino
14 | board = adafruit_feather_m0
15 |
16 | ;[env:due]
17 | platform = atmelsam
18 | framework = arduino
19 | board = due
20 |
21 | ;[env:dueUSB]
22 | platform = atmelsam
23 | framework = arduino
24 | board = dueUSB
25 |
26 | ;[env:digix]
27 | platform = atmelsam
28 | framework = arduino
29 | board = digix
30 |
31 | [env:mkr1000USB]
32 | platform = atmelsam
33 | framework = arduino
34 | board = mkr1000USB
35 |
36 | [env:mkrzero]
37 | platform = atmelsam
38 | framework = arduino
39 | board = mkrzero
40 |
41 | [env:mzeropro]
42 | platform = atmelsam
43 | framework = arduino
44 | board = mzeropro
45 |
46 | [env:mzeroUSB]
47 | platform = atmelsam
48 | framework = arduino
49 | board = mzeroUSB
50 |
51 | [env:sodaq_autonomo]
52 | platform = atmelsam
53 | framework = arduino
54 | board = sodaq_autonomo
55 |
56 | [env:sparkfun_samd21_mini_usb]
57 | platform = atmelsam
58 | framework = arduino
59 | board = sparkfun_samd21_mini_usb
60 |
61 | [env:tian]
62 | platform = atmelsam
63 | framework = arduino
64 | board = tian
65 |
66 | [env:zero]
67 | platform = atmelsam
68 | framework = arduino
69 | board = zero
70 |
71 | [env:zeroUSB]
72 | platform = atmelsam
73 | framework = arduino
74 | board = zeroUSB
75 |
--------------------------------------------------------------------------------
/examples/universal-lwmqtt/universal-lwmqtt.ino:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // !!REPLACEME!!
16 | // The MQTT callback function for commands and configuration updates
17 | // Place your message handler code here.
18 | void messageReceived(String &topic, String &payload) {
19 | Serial.println("incoming: " + topic + " - " + payload);
20 | }
21 |
22 | #include "universal-mqtt.h"
23 |
24 | void setup() {
25 | // put your setup code here, to run once:
26 | Serial.begin(115200);
27 | pinMode(LED_BUILTIN, OUTPUT);
28 | setupCloudIoT();
29 | }
30 |
31 | unsigned long lastMillis = 0;
32 | void loop() {
33 | mqtt->loop();
34 | delay(10); // <- fixes some issues with WiFi stability
35 |
36 | if (!mqttClient->connected()) {
37 | connect();
38 | }
39 |
40 | // publish a message roughly every second.
41 | if (millis() - lastMillis > 1000) {
42 | lastMillis = millis();
43 | publishTelemetry(getDefaultSensor());
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/examples/MKR1000-lwmqtt/MKR1000-lwmqtt.ino:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 |
16 | #if defined(ESP8266) or defined(ESP32)
17 | #define __SKIP_MKR1000__
18 | #endif
19 |
20 | #if defined(ARDUINO_SAMD_MKR1000)
21 | #define __MKR1000_MQTT_H__
22 | #endif
23 |
24 | #ifdef __SKIP_MKR1000__
25 |
26 | #include
27 |
28 | void setup(){
29 | Serial.begin(115200);
30 | }
31 |
32 | void loop(){
33 | Serial.println("Hello World");
34 | }
35 |
36 | #endif
37 |
38 | #ifdef __MKR1000_MQTT_H__
39 | #include "mkr1000-mqtt.h"
40 | void setup() {
41 | // put your setup code here, to run once:
42 | Serial.begin(9600);
43 | pinMode(LED_BUILTIN, OUTPUT);
44 | setupCloudIoT();
45 | }
46 |
47 | unsigned long lastMillis = 0;
48 | void loop() {
49 | mqtt->loop();
50 | delay(10); // <- fixes some issues with WiFi stability
51 |
52 | if (!mqttClient->connected()) {
53 | connect();
54 | }
55 |
56 | // publish a message roughly every second.
57 | if (millis() - lastMillis > 1000) {
58 | lastMillis = millis();
59 | publishTelemetry(getDefaultSensor());
60 | }
61 | }
62 | #endif
--------------------------------------------------------------------------------
/examples/complex/esp32/Gateway/Esp32-gateway/Esp32-gateway.ino:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2020 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | #if defined(ESP8266) or defined(ARDUINO_SAMD_MKR1000)
16 | #define __SKIP_ESP32__
17 | #endif
18 |
19 | #if defined(ESP32)
20 | #define __ESP32_MQTT__
21 | #endif
22 |
23 | #ifdef __SKIP_ESP32__
24 |
25 | #include
26 |
27 | void setup(){
28 | Serial.begin(115200);
29 | }
30 |
31 | void loop(){
32 | Serial.println("Hello World");
33 | }
34 |
35 | #endif
36 |
37 | #ifdef __ESP32_MQTT__
38 |
39 | #include "esp32-mqtt.h"
40 |
41 | unsigned long lastMillis = millis();
42 |
43 | void setup() {
44 | Serial.begin(115200);
45 | setupCloudIoT();
46 | }
47 |
48 | void loop() {
49 | mqtt->loop();
50 | delay(10); // <- fixes some issues with WiFi stability
51 |
52 | // This is where the problem is when mqtt calls mqttConnect
53 | if (!mqttClient->connected()) {
54 | connect();
55 | }
56 |
57 | if (millis() - lastMillis > 60000) {
58 | lastMillis = millis();
59 | //publishTelemetry(mqttClient, "/sensors", getDefaultSensor());
60 | pollDelegate();
61 | }
62 | }
63 |
64 | #endif
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/LottieView.swift:
--------------------------------------------------------------------------------
1 | //**************************************************************************
2 | // Copyright 2020 Google
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // 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
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | // *****************************************************************************/
15 |
16 | import SwiftUI
17 | import Lottie
18 |
19 | struct LottieView: UIViewRepresentable {
20 | func updateUIView(_ uiView: UIView, context: Context) {
21 | }
22 |
23 | let animationView = AnimationView()
24 | var filename = "LottieLogo2"
25 |
26 | func makeUIView(context: UIViewRepresentableContext) -> UIView {
27 | let view = UIView()
28 |
29 | let animation = Animation.named(filename)
30 | animationView.animation = animation
31 | animationView.contentMode = .scaleAspectFit
32 | animationView.loopMode = .loop.self
33 | animationView.play()
34 |
35 |
36 | animationView.translatesAutoresizingMaskIntoConstraints = false
37 | view.addSubview(animationView)
38 |
39 | NSLayoutConstraint.activate([
40 | animationView.heightAnchor.constraint(equalTo: view.heightAnchor),
41 | animationView.widthAnchor.constraint(equalTo: view.widthAnchor)
42 | ])
43 | return view
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/examples/Esp32-lwmqtt/Esp32-lwmqtt.ino:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 |
16 | #if defined(ARDUINO_SAMD_MKR1000) or defined(ESP8266)
17 | #define __SKIP_ESP32__
18 | #endif
19 |
20 | #if defined(ESP32)
21 | #define __ESP32_MQTT_H__
22 | #endif
23 |
24 | #ifdef __SKIP_ESP32__
25 |
26 | #include
27 |
28 | void setup(){
29 | Serial.begin(115200);
30 | }
31 |
32 | void loop(){
33 | Serial.println("Hello World");
34 | }
35 |
36 | #endif
37 |
38 | #ifdef __ESP32_MQTT_H__
39 | #include "esp32-mqtt.h"
40 | void setup() {
41 | // put your setup code here, to run once:
42 | Serial.begin(115200);
43 | pinMode(LED_BUILTIN, OUTPUT);
44 | setupCloudIoT();
45 | }
46 |
47 | unsigned long lastMillis = 0;
48 | void loop() {
49 | mqtt->loop();
50 | delay(10); // <- fixes some issues with WiFi stability
51 |
52 | if (!mqttClient->connected()) {
53 | connect();
54 | }
55 |
56 | // TODO: replace with your code
57 | // publish a message roughly every second.
58 | if (millis() - lastMillis > 60000) {
59 | lastMillis = millis();
60 | //publishTelemetry(mqttClient, "/sensors", getDefaultSensor());
61 | publishTelemetry(getDefaultSensor());
62 | }
63 | }
64 | #endif
--------------------------------------------------------------------------------
/src/crypto/ecdsa.h:
--------------------------------------------------------------------------------
1 | // AUTOGENERATED, DO NOT EDIT. See CONTRIBUTING.md for instructions.
2 | #define SHA256_DIGEST_LENGTH 32
3 | /**
4 | * \defgroup ecdsa Elliptic Curve Digital Signature Algorithm
5 | *
6 | * @{
7 | */
8 |
9 | /**
10 | * \file
11 | * Header file for the Elliptic Curve Digital Signature Algorithm functions.
12 | * \author
13 | * Kasun Hewage
14 | *
15 | */
16 |
17 | #ifndef __EDSA_H__
18 | #define __EDSA_H__
19 |
20 | #include "nn.h"
21 | #include "ecc.h"
22 |
23 | /**
24 | * \brief Initialize the ECDSA using the public key that is to be
25 | * used to verify the signature.
26 | *
27 | * \param pb_key A pointer to the public key.
28 | * This public key may not be generated from the private
29 | * key whose key is used to verify the signature.
30 | */
31 | void ecdsa_init(point_t * pb_key);
32 |
33 | /**
34 | * \brief Sign a message using the private key.
35 | *
36 | * \param sha256sum Hash of the message to sign.
37 | * \param r
38 | * \param s Signature of the message.
39 | * \param pr_key The private key that is used to sign the message.
40 | */
41 | void ecdsa_sign(uint8_t sha256sum[SHA256_DIGEST_LENGTH], NN_DIGIT *r, NN_DIGIT *s, NN_DIGIT * pr_key);
42 |
43 | /**
44 | * \brief Verify a message using public key.
45 | * \param sha256sum Hash of the message to sign.
46 | * \param r
47 | * \param s Signature of the message.
48 | * \param pb_key The public key that is used to verify the signature.
49 | * EDSA should be initialized by using this public key prior
50 | * to verify.
51 | * \return 1 if the signature is verified.
52 | * \sa ecdsa_init
53 | */
54 | uint8_t ecdsa_verify(uint8_t sha256sum[SHA256_DIGEST_LENGTH], NN_DIGIT *r, NN_DIGIT *s, point_t * pb_key);
55 |
56 |
57 | #endif /* __EDSA_H__ */
58 |
59 | /** @} */
60 |
--------------------------------------------------------------------------------
/examples/Esp8266-lwmqtt/Esp8266-lwmqtt.ino:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 |
16 | #if defined(ARDUINO_SAMD_MKR1000) or defined(ESP32)
17 | #define __SKIP_ESP8266__
18 | #endif
19 |
20 | #if defined(ESP8266)
21 | #define __ESP8266_MQTT__
22 | #endif
23 |
24 | #ifdef __SKIP_ESP8266__
25 |
26 | #include
27 |
28 | void setup(){
29 | Serial.begin(115200);
30 | }
31 |
32 | void loop(){
33 | Serial.println("Hello World");
34 | }
35 |
36 | #endif
37 |
38 | #ifdef __ESP8266_MQTT__
39 | #include
40 | #include "esp8266_mqtt.h"
41 |
42 | #ifndef LED_BUILTIN
43 | #define LED_BUILTIN 13
44 | #endif
45 |
46 | void setup()
47 | {
48 | // put your setup code here, to run once:
49 | Serial.begin(115200);
50 | setupCloudIoT(); // Creates globals for MQTT
51 | pinMode(LED_BUILTIN, OUTPUT);
52 | }
53 |
54 | static unsigned long lastMillis = 0;
55 | void loop()
56 | {
57 | if (!mqtt->loop())
58 | {
59 | mqtt->mqttConnect();
60 | }
61 |
62 | delay(10); // <- fixes some issues with WiFi stability
63 |
64 | // TODO: Replace with your code here
65 | if (millis() - lastMillis > 60000)
66 | {
67 | lastMillis = millis();
68 | publishTelemetry(getDefaultSensor());
69 | }
70 | }
71 | #endif
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/examples/complex/esp32/Gateway/Esp32-gateway/connect-serial.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2020 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | #include "BluetoothSerial.h"
16 |
17 | BluetoothSerial SerialBT;
18 |
19 | static String staticBTDeviceID = "";
20 | bool connected;
21 |
22 | void setupSerialBT() {
23 | //SerialBT.setPin(pin);
24 | delay(5000);
25 | SerialBT.begin("my-esp32-gateway",true);
26 | //SerialBT.setPin(pin);
27 | Serial.println("The device started in master mode, make sure remote BT device is on!");
28 |
29 | // Note: connect(address) is fast (up to 10 secs max), connect(name) is slow (upto 30 secs max) as it needs
30 | // to resolve name to address first, but it allows to connect to different devices with the same name.
31 | // Set CoreDebugLevel to Info to view devices bluetooth address and device names.
32 | // connected = SerialBT.connect(address); // for cases where you want to use connect(name)
33 | connected = SerialBT.connect(staticBTDeviceID);
34 |
35 | if(connected) {
36 | Serial.println("Connected Succesfully!");
37 | } else {
38 | while(!SerialBT.connected(10000)) {
39 | Serial.println("Failed to connect. Make sure remote device is available and in range, then restart app.");
40 | }
41 | }
42 | }
43 |
44 | void disconnectSerialBT() {
45 | if(SerialBT.disconnect()) {
46 | Serial.println("Disconnected!");
47 | }
48 | }
49 |
50 | void forwardComand(String payload) {
51 | SerialBT.println(payload);
52 | }
53 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //**************************************************************************
2 | // Copyright 2020 Google
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // 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
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | // *****************************************************************************/
15 |
16 | import UIKit
17 |
18 | @UIApplicationMain
19 | class AppDelegate: UIResponder, UIApplicationDelegate {
20 |
21 |
22 |
23 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
24 | // Override point for customization after application launch.
25 | return true
26 | }
27 |
28 | // MARK: UISceneSession Lifecycle
29 |
30 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
31 | // Called when a new scene session is being created.
32 | // Use this method to select a configuration to create the new scene with.
33 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
34 | }
35 |
36 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
37 | // Called when the user discards a scene session.
38 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
39 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
40 | }
41 |
42 |
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | NSBluetoothAlwaysUsageDescription
24 | Always On
25 | UIApplicationSceneManifest
26 |
27 | UIApplicationSupportsMultipleScenes
28 |
29 | UISceneConfigurations
30 |
31 | UIWindowSceneSessionRoleApplication
32 |
33 |
34 | UISceneConfigurationName
35 | Default Configuration
36 | UISceneDelegateClassName
37 | $(PRODUCT_MODULE_NAME).SceneDelegate
38 | UISceneStoryboardFile
39 | Main
40 |
41 |
42 |
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIMainStoryboardFile
47 | Main
48 | UIRequiredDeviceCapabilities
49 |
50 | armv7
51 |
52 | UISupportedInterfaceOrientations
53 |
54 | UIInterfaceOrientationPortrait
55 |
56 | UISupportedInterfaceOrientations~ipad
57 |
58 | UIInterfaceOrientationPortrait
59 | UIInterfaceOrientationPortraitUpsideDown
60 | UIInterfaceOrientationLandscapeLeft
61 | UIInterfaceOrientationLandscapeRight
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/examples/MKR1000-lwmqtt/ciotc_config.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // This file contains your configuration used to connect to Cloud IoT Core
16 |
17 | // Important!
18 | // TODO(you): Install root certificate to verify tls connection as described
19 | // in https://www.hackster.io/arichetta/add-ssl-certificates-to-mkr1000-93c89d
20 |
21 | // Wifi network details.
22 | const char* ssid = "YOUR_SSID";
23 | const char* password = "YOUR_PASSWORD";
24 |
25 | // Cloud iot details.
26 | const char* project_id = "YOUR-PROJECT-ID";
27 | const char* location = "us-central1";
28 | const char* registry_id = "YOUR-REGISTRY-ID";
29 | const char* device_id = "YOUR-DEVICE-ID";
30 |
31 | // To get the private key run (where private-key.pem is the ec private key
32 | // used to create the certificate uploaded to google cloud iot):
33 | // openssl ec -in -noout -text
34 | // and copy priv: part.
35 | // The key length should be exactly the same as the key length bellow (32 pairs
36 | // of hex digits). If it's bigger and it starts with "00:" delete the "00:". If
37 | // it's smaller add "00:" to the start. If it's too big or too small something
38 | // is probably wrong with your key.
39 | const char* private_key_str =
40 | "5a:2e:06:b5:c1:f2:9c:b3:77:b2:89:f5:29:29:93:"
41 | "07:fd:ed:22:0d:03:2b:a6:b1:b6:04:0b:d5:9b:49:"
42 | "7d:ca";
43 |
44 | // Time (seconds) to expire token += 20 minutes for drift
45 | const int jwt_exp_secs = 3600; // Maximum 24H (3600*24)
46 |
47 | // In case we ever need extra topics
48 | const int ex_num_topics = 0;
49 | const char* ex_topics[ex_num_topics];
50 | //const int ex_num_topics = 1;
51 | //const char* ex_topics[ex_num_topics] = {
52 | // "/devices/my-device/tbd/#"
53 | //};
54 |
--------------------------------------------------------------------------------
/examples/complex/esp32/camera/base64.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2019 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 |
16 |
17 | static const char* base64_chars =
18 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
19 | "abcdefghijklmnopqrstuvwxyz"
20 | "0123456789+/";
21 |
22 | // Forward declaration for base64 function from jwt.cpp
23 | void my_base64_encode(const unsigned char *bytes_to_encode,
24 | unsigned int in_len) {
25 | int i = 0;
26 | int j = 0;
27 | unsigned char char_array_3[3];
28 | unsigned char char_array_4[4];
29 |
30 | File file = SPIFFS.open("/b64image.txt", FILE_WRITE);
31 | if (!file) {
32 | Serial.println("There was an error opening the file for write");
33 | return;
34 | }
35 |
36 | while (in_len--) {
37 | char_array_3[i++] = *(bytes_to_encode++);
38 | if (i == 3) {
39 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
40 | char_array_4[1] =
41 | ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
42 | char_array_4[2] =
43 | ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
44 | char_array_4[3] = char_array_3[2] & 0x3f;
45 |
46 | for (i = 0; (i < 4); i++) {
47 | file.print(base64_chars[char_array_4[i]]);
48 | }
49 | i = 0;
50 | }
51 | }
52 |
53 | if (i) {
54 | for (j = i; j < 3; j++) {
55 | char_array_3[j] = '\0';
56 | }
57 |
58 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
59 | char_array_4[1] =
60 | ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
61 | char_array_4[2] =
62 | ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
63 | char_array_4[3] = char_array_3[2] & 0x3f;
64 |
65 | for (j = 0; (j < i + 1); j++) {
66 | file.print(base64_chars[char_array_4[j]]);
67 | }
68 |
69 | while ((i++ < 3)) {
70 | file.print('=');
71 | }
72 | }
73 |
74 | file.close();
75 | }
76 |
--------------------------------------------------------------------------------
/src/CloudIoTCoreMqtt.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2019 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | #ifndef __CLOUDIOTCORE_MQTT_H__
16 | #define __CLOUDIOTCORE_MQTT_H__
17 | #include
18 | #include "CloudIoTCore.h"
19 | #include "CloudIoTCoreDevice.h"
20 | #include
21 | #include
22 |
23 | class CloudIoTCoreMqtt {
24 | private:
25 | int __backoff__ = 1000; // current backoff, milliseconds
26 | static const int __factor__ = 2.5f;
27 | static const int __minbackoff__ = 1000; // minimum backoff, ms
28 | static const int __max_backoff__ = 60000; // maximum backoff, ms
29 | static const int __jitter__ = 500; // max random jitter, ms
30 | boolean logConnect = true;
31 | boolean useLts = false;
32 |
33 | MQTTClient *mqttClient;
34 | Client *netClient;
35 | CloudIoTCoreDevice *device;
36 |
37 | public:
38 | CloudIoTCoreMqtt(MQTTClient *mqttClient, Client *netClient, CloudIoTCoreDevice *device);
39 |
40 | boolean loop();
41 | void mqttConnect(bool skip = false);
42 | void mqttConnectAsync(bool skip = false);
43 | void startMQTT();
44 | void startMQTTAdvanced();
45 |
46 | bool publishTelemetry(const String &data);
47 | bool publishTelemetry(const String &data, int qos);
48 | bool publishTelemetry(const char* data, int length);
49 | bool publishTelemetry(const String &subtopic, const String &data);
50 | bool publishTelemetry(const String &subtopic, const String &data, int qos);
51 | bool publishTelemetry(const String &subtopic, const char* data, int length);
52 | bool publishState(const String &data);
53 | bool publishState(const char* data);
54 | bool publishState(const char* data, int length);
55 |
56 | void logConfiguration(bool showJWT);
57 | void logError();
58 | void logReturnCode();
59 |
60 | void onConnect();
61 | void setLogConnect(boolean enabled);
62 | void setUseLts(boolean enabled);
63 | };
64 | #endif // __CLOUDIOTCORE_MQTT_H__
65 |
--------------------------------------------------------------------------------
/src/CloudIoTCoreDevice.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 |
16 | #ifndef CloudIoTCoreDevice_h
17 | #define CloudIoTCoreDevice_h
18 |
19 | #include
20 | #include "jwt.h"
21 |
22 | class CloudIoTCoreDevice {
23 | private:
24 | const char *project_id;
25 | const char *location;
26 | const char *registry_id;
27 | const char *device_id;
28 |
29 | NN_DIGIT priv_key[9];
30 | String jwt;
31 | int jwt_exp_secs;
32 | unsigned long exp_millis = 0;
33 |
34 | String getBasePath();
35 |
36 | public:
37 | CloudIoTCoreDevice();
38 | CloudIoTCoreDevice(const char *project_id, const char *location,
39 | const char *registry_id, const char *device_id);
40 | CloudIoTCoreDevice(const char *project_id, const char *location,
41 | const char *registry_id, const char *device_id,
42 | const char *private_key);
43 |
44 | CloudIoTCoreDevice &setProjectId(const char *project_id);
45 | CloudIoTCoreDevice &setLocation(const char *location);
46 | CloudIoTCoreDevice &setRegistryId(const char *registry_id);
47 | CloudIoTCoreDevice &setDeviceId(const char *device_id);
48 | CloudIoTCoreDevice &setPrivateKey(const char *private_key);
49 | CloudIoTCoreDevice &setPrivateKey(const unsigned char *private_key);
50 | void setJwtExpSecs(int exp_in_secs);
51 | int getJwtExpSecs();
52 | unsigned long getExpMillis();
53 | String createJWT(long long int time);
54 | String createJWT(long long int time, int jwt_in_time);
55 | String getJWT();
56 |
57 | /* HTTP methods path */
58 | String getConfigPath(int version);
59 | String getLastConfigPath();
60 | String getSendTelemetryPath();
61 | String getSetStatePath();
62 |
63 | /* MQTT methods */
64 | String getClientId();
65 | String getCommandsTopic();
66 | String getConfigTopic();
67 | String getDeviceId();
68 | String getEventsTopic();
69 | String getStateTopic();
70 | };
71 | #endif // CloudIoTCoreDevice_h
72 |
--------------------------------------------------------------------------------
/pull_crypto.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #******************************************************************************
3 | # Copyright 2018 Google
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #****************************************************************************
16 |
17 |
18 | # This script pulls the latest source files from github into the jwt/crypto
19 | # folder. Run it from it's directory to get the latest files.
20 |
21 | # Make temp directory, cd into it.
22 | mkdir tmp
23 | cd tmp
24 |
25 | # Clone ecc libraries.
26 | git clone https://github.com/cirvladimir/ecc-light-certificate.git
27 | git clone https://github.com/CSSHL/ESP8266-Arduino-cryptolibs.git
28 |
29 | # cd out of tmp.
30 | cd ..
31 |
32 | # Copy sources into jwt folder.
33 | cp tmp/ESP8266-Arduino-cryptolibs/sha256/sha256.cpp src/crypto/sha256.cpp
34 | cp tmp/ESP8266-Arduino-cryptolibs/sha256/sha256.h src/crypto/sha256.h
35 | cp tmp/ecc-light-certificate/ecc/curve-params/secp256r1.c src/crypto/secp256r1.cpp
36 | cp tmp/ecc-light-certificate/ecc/ecc.c src/crypto/ecc.cpp
37 | cp tmp/ecc-light-certificate/ecc/ecc.h src/crypto/ecc.h
38 | cp tmp/ecc-light-certificate/ecc/ecdsa.c src/crypto/ecdsa.cpp
39 | cp tmp/ecc-light-certificate/ecc/ecdsa.h src/crypto/ecdsa.h
40 | cp tmp/ecc-light-certificate/ecc/nn.c src/crypto/nn.cpp
41 | cp tmp/ecc-light-certificate/ecc/nn.h src/crypto/nn.h
42 |
43 | # Remove unnecessary sha library.
44 | sed -i '/#include "sha2.h"/d' src/crypto/ecdsa.h
45 | # Add some defines since we're not using make.
46 | sed -i '1i#define SHA256_DIGEST_LENGTH 32' src/crypto/ecdsa.h
47 | sed -i '1i#define THIRTYTWO_BIT_PROCESSOR' src/crypto/nn.h
48 | sed -i '1i#define SECP256R1' src/crypto/nn.h
49 |
50 | # Change string.h to String.h
51 | for f in src/crypto/ecdsa.cpp src/crypto/nn.cpp src/crypto/secp256r1.cpp src/crypto/sha256.cpp
52 | do
53 | sed -i 's/#include /#include /' $f
54 | done
55 |
56 | # Add a do not edit comment.
57 | for f in src/crypto/sha256.cpp src/crypto/sha256.h src/crypto/secp256r1.cpp src/crypto/ecc.cpp src/crypto/ecc.h src/crypto/ecdsa.cpp src/crypto/ecdsa.h src/crypto/nn.cpp src/crypto/nn.h
58 | do
59 | sed -i '1i// AUTOGENERATED, DO NOT EDIT. See CONTRIBUTING.md for instructions.' $f
60 | done
61 |
62 | rm -rf tmp
63 |
--------------------------------------------------------------------------------
/examples/complex/esp32/camera/README.md:
--------------------------------------------------------------------------------
1 | # ESP32 (m5-stack) Camera demo
2 |
3 | This demo uses the inexpensive and readily available M5-stack camera to send
4 | images to Google Cloud IoT core and publish to PubSub. You can then process the
5 | images from PubSub. For example, you can store images in Google Cloud Storage,
6 | detect labels with the vision API, or render the images to a client.
7 |
8 | **Disclaimer** This demo is still in a rough state, can crash the ESP32 and is
9 | offered with limited support. There are a lot of different models for the ESP32
10 | camera, so ymmv with the provided configurations.
11 |
12 | Some of the camera code is based on the [Randomnerdtutorials](https://randomnerdtutorials.com/esp32-cam-video-streaming-web-server-camera-home-assistant/) example
13 | that shows you how to configure the camera for use with the ESP-IDF driver.
14 |
15 | ## Configuration
16 | You need to configure the camera pins in `camera.ino` to match the
17 | configuration for your particular model. The example configurations reflect
18 | models encountered during testing but you may need to add your own based on
19 | the data sheet for your device.
20 |
21 | Update the values in [ciotc_config.h](ciotc_config.h) so that they match the
22 | configuration for your device. More information on this can be found in the
23 | library readme.
24 |
25 | ## Running the demo
26 | After your device is connected, either send a command to your device or open
27 | the serial monitor and send a message to the device. The device will send
28 | an image to the configured PubSub topic and you can from there process the
29 | image using a subscriber.
30 |
31 | For testing, it's easier to base64 encode the image by replacing the following
32 | line:
33 |
34 | ```cpp
35 | publishTelemetry((char*)_jpg_buf, frame_size);
36 | ```
37 |
38 | With the following code to encode and transmit the file:
39 |
40 | ```cpp
41 | // Encode the temp data to file system
42 | my_base64_encode(_jpg_buf, frame_size);
43 | publishTelemetryFromFile();
44 | ```
45 |
46 | You must also setup SPIFFS on the device and create an empty SPIFFS image using
47 | the [ESP32 FS plugin](https://github.com/me-no-dev/arduino-esp32fs-plugin).
48 |
49 | After you pull the message from the PubSub topic, you can Base64 decode the
50 | image to produce the file. For example, on BSD/Unix/Linux systems, you can
51 | use the built-in utility base64:
52 |
53 | ```bash
54 | echo "base64-encoded-bytes" | base64 -d > image.jpg
55 | ```
56 |
57 | ## Troubleshooting
58 | If the MQTT connection is resetting when you transmit the image, you may want
59 | to try tweaking the buffer for the MQTT client which is set when
60 | the client is initialized in `esp32-mqtt.h`. The buffer size for the image is
61 | printed to the serial line so that you can have an idea of an appropriate value
62 | to use. You can also try using a different image size, by replacing the value
63 | set on `config.framesize`. For example, you can try the smaller
64 | `FRAMESIZE_QVGA` format.
65 |
--------------------------------------------------------------------------------
/examples/complex/esp32/Gateway/README.md:
--------------------------------------------------------------------------------
1 | # ESP32 Gateway demo
2 |
3 | This demo uses two inexpensive and readily available ESP32 devices to send and receive
4 | data from Google Cloud. The device with a connection to Google Cloud (Gateway) will
5 | communicate on behalf of other devices (delegate devices).
6 | The gateway will send the data to Google Cloud IoT core and publish to PubSub.
7 | For example, you can send temperature data from multiple delegate devices to Google Cloud and store that information to see
8 | any drastic temperature changes in a room.
9 |
10 | **Disclaimer** This demo is not a robust solution, can crash the ESP32, and is offered with limited support.
11 |
12 | Some of the SerialBT code is based on [Espressif](https://github.com/espressif/arduino-esp32/tree/master/libraries/BluetoothSerial/examples/) examples
13 | that shows you how to connect two devices over serial bluetooth.
14 |
15 | ## Configuration
16 |
17 | Create a gateway and a delegate device, make sure that the both devices are setup on the cloud and that the delegate device is bound to the gateway.
18 |
19 | Specify the devices that connect over bluetooth in `ESP32_delegate.ino`. These devices
20 | must correspond to devices created in the [Cloud IoT Core section of the Cloud Console](https://console.cloud.google.com/iot).
21 | The example IDs correspond to the device_id on the Google Cloud IoT core.
22 |
23 | Update the values in [ciotc_config.h](ciotc_config.h) so that they match the
24 | configuration for your gateway device and delegate devices.
25 |
26 | ## Running the demo
27 | Flash the gateway device with the project sources in Esp32-Gateway and delegate device(s) with the project sources in Esp32-delegate,
28 | then restart both devices.After your gateway device is connected, you can now send an attach command
29 | which will attach the delegate devices found in [ciotc_config.h](ciotc_config.h).
30 | Once you delegate devices are attached you can send a command to your devices from the cloud,
31 | the command must follow the following order and structure:
32 |
33 | deviceid,command,data;
34 |
35 | For the example the commands you can send are the following:
36 |
37 | deviceid,event,get temperature;
38 | deviceid,state,get state;
39 |
40 | The gateway device will connect to the delegate over bluetooth and forward this command to the delegate device,
41 | then the gateway will receive the response and publish to the PubSub subscription.
42 |
43 | After you pull the message from the PubSub topic, you should then see the temperature read out or the state of the device depending on the command you sent.
44 |
45 | ## Troubleshooting
46 | If the MQTT connection is resetting when you're attaching the delegate devices,
47 | make sure that your delegate devices are bound to the gateway and that the gateway is configured to use association-only in the [Cloud Console](https://console.cloud.google.com/iot?pli=1).
48 |
49 | Note that if you are attaching more than 10 delegate devices to the gateway, you should increase the timeout in `ciotc_config.h`.
50 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //**************************************************************************
2 | // Copyright 2020 Google
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // 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
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | // *****************************************************************************/
15 |
16 | import UIKit
17 | import SwiftUI
18 |
19 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
20 |
21 | var window: UIWindow?
22 |
23 |
24 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
25 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
26 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
27 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
28 | guard let _ = (scene as? UIWindowScene) else { return }
29 | }
30 |
31 | func sceneDidDisconnect(_ scene: UIScene) {
32 | // Called as the scene is being released by the system.
33 | // This occurs shortly after the scene enters the background, or when its session is discarded.
34 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
35 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
36 | }
37 |
38 | func sceneDidBecomeActive(_ scene: UIScene) {
39 | // Called when the scene has moved from an inactive state to an active state.
40 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
41 | }
42 |
43 | func sceneWillResignActive(_ scene: UIScene) {
44 | // Called when the scene will move from an active state to an inactive state.
45 | // This may occur due to temporary interruptions (ex. an incoming phone call).
46 | }
47 |
48 | func sceneWillEnterForeground(_ scene: UIScene) {
49 | // Called as the scene transitions from the background to the foreground.
50 | // Use this method to undo the changes made on entering the background.
51 | }
52 |
53 | func sceneDidEnterBackground(_ scene: UIScene) {
54 | // Called as the scene transitions from the foreground to the background.
55 | // Use this method to save data, release shared resources, and store enough scene-specific state information
56 | // to restore the scene back to its current state.
57 | }
58 |
59 |
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client.xcodeproj/xcshareddata/xcschemes/iOS_IoTCore_Client.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/examples/complex/esp32/camera/esp32-mqtt.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2019 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // This file contains static methods for API requests using Wifi / MQTT
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 |
22 | #include
23 | #include
24 | #include "ciotc_config.h" // Update this file with your configuration
25 |
26 | // Initialize WiFi and MQTT for this board
27 | Client *netClient;
28 | CloudIoTCoreDevice *device;
29 | CloudIoTCoreMqtt *mqtt;
30 | MQTTClient *mqttClient;
31 | unsigned long iat = 0;
32 | String jwt;
33 |
34 | ///////////////////////////////
35 | // Helpers specific to this board
36 | ///////////////////////////////
37 | String getDefaultSensor() {
38 | return "Wifi: " + String(WiFi.RSSI()) + "db";
39 | }
40 |
41 | String getJwt() {
42 | iat = time(nullptr);
43 | Serial.println("Refreshing JWT");
44 | jwt = device->createJWT(iat, jwt_exp_secs);
45 | return jwt;
46 | }
47 |
48 | void setupWifi() {
49 | Serial.println("Starting wifi");
50 |
51 | WiFi.mode(WIFI_STA);
52 | // WiFi.setSleep(false); // May help with disconnect? Seems to have been removed from WiFi
53 | WiFi.begin(ssid, password);
54 | Serial.println("Connecting to WiFi");
55 | while (WiFi.status() != WL_CONNECTED) {
56 | delay(100);
57 | }
58 |
59 | configTime(0, 0, ntp_primary, ntp_secondary);
60 | Serial.println("Waiting on time sync...");
61 | while (time(nullptr) < 1510644967) {
62 | delay(10);
63 | }
64 | Serial.println("Wifi setup complete");
65 | }
66 |
67 | void connectWifi() {
68 | Serial.print("checking wifi...");
69 | while (WiFi.status() != WL_CONNECTED) {
70 | Serial.print(".");
71 | delay(1000);
72 | }
73 | }
74 |
75 | ///////////////////////////////
76 | // Orchestrates various methods from preceeding code.
77 | ///////////////////////////////
78 | bool publishTelemetry(String data) {
79 | return mqtt->publishTelemetry(data);
80 | }
81 |
82 | bool publishTelemetry(const char* data, int length) {
83 | return mqtt->publishTelemetry(data, length);
84 | }
85 |
86 | bool publishTelemetry(String subfolder, String data) {
87 | return mqtt->publishTelemetry(subfolder, data);
88 | }
89 |
90 | bool publishTelemetry(String subfolder, const char* data, int length) {
91 | return mqtt->publishTelemetry(subfolder, data, length);
92 | }
93 |
94 | void connect() {
95 | connectWifi();
96 | mqtt->mqttConnect();
97 | }
98 |
99 | void setupCloudIoT() {
100 | device = new CloudIoTCoreDevice(
101 | project_id, location, registry_id, device_id,
102 | private_key_str);
103 |
104 | setupWifi();
105 | netClient = new WiFiClientSecure();
106 | mqttClient = new MQTTClient(34000);
107 | mqttClient->setOptions(180, true, 1000); // keepAlive, cleanSession, timeout
108 | mqtt = new CloudIoTCoreMqtt(mqttClient, netClient, device);
109 | mqtt->setUseLts(true);
110 | mqtt->setLogConnect(false); // To avoid pushing invalid messages
111 | mqtt->startMQTT();
112 | }
113 |
--------------------------------------------------------------------------------
/examples/MKR1000-lwmqtt/mkr1000-mqtt.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // This file contains static methods for API requests using Wifi / MQTT
16 | #include
17 | #include
18 |
19 | #include
20 |
21 | #include
22 | #include
23 | #include "ciotc_config.h" // Update this file with your configuration
24 |
25 | // !!REPLACEME!!
26 | // The MQTT callback function for commands and configuration updates
27 | // Place your message handler code here.
28 | void messageReceived(String &topic, String &payload) {
29 | Serial.println("incoming: " + topic + " - " + payload);
30 | }
31 | ///////////////////////////////
32 |
33 | // Cloud IoT configuration that you don't need to change
34 | Client *netClient;
35 | CloudIoTCoreDevice *device;
36 | CloudIoTCoreMqtt *mqtt;
37 | MQTTClient *mqttClient;
38 | unsigned long iat = 0;
39 | String jwt;
40 |
41 | ///////////////////////////////
42 | // Helpers specific to this board
43 | ///////////////////////////////
44 | String getDefaultSensor() {
45 | return "Wifi: " + String(WiFi.RSSI()) + "db";
46 | }
47 |
48 | String getJwt() {
49 | // Disable software watchdog as these operations can take a while.
50 | Serial.println("Refreshing JWT");
51 | iat = WiFi.getTime();
52 | jwt = device->createJWT(iat, jwt_exp_secs);
53 | return jwt;
54 | }
55 |
56 | void setupWifi() {
57 | Serial.println("Starting wifi");
58 |
59 | WiFi.begin(ssid, password);
60 | Serial.println("Connecting to WiFi");
61 | while (WiFi.status() != WL_CONNECTED) {
62 | delay(100);
63 | }
64 |
65 | Serial.println("Waiting on time sync...");
66 | while (WiFi.getTime() < 1510644967) {
67 | delay(10);
68 | }
69 | }
70 |
71 | void connectWifi() {
72 | Serial.print("checking wifi...");
73 | while (WiFi.status() != WL_CONNECTED) {
74 | Serial.print(".");
75 | delay(1000);
76 | }
77 | }
78 |
79 | ///////////////////////////////
80 | // Orchestrates various methods from preceeding code.
81 | ///////////////////////////////
82 | bool publishTelemetry(String data) {
83 | return mqtt->publishTelemetry(data);
84 | }
85 |
86 | bool publishTelemetry(const char* data, int length) {
87 | return mqtt->publishTelemetry(data, length);
88 | }
89 |
90 | bool publishTelemetry(String subfolder, String data) {
91 | return mqtt->publishTelemetry(subfolder, data);
92 | }
93 |
94 | bool publishTelemetry(String subfolder, const char* data, int length) {
95 | return mqtt->publishTelemetry(subfolder, data, length);
96 | }
97 |
98 | void connect() {
99 | connectWifi();
100 | mqtt->mqttConnect();
101 | }
102 |
103 | void setupCloudIoT() {
104 | device = new CloudIoTCoreDevice(
105 | project_id, location, registry_id, device_id,
106 | private_key_str);
107 |
108 | setupWifi();
109 | netClient = new WiFiSSLClient();
110 |
111 | mqttClient = new MQTTClient(512);
112 | mqttClient->setOptions(180, true, 1000); // keepAlive, cleanSession, timeout
113 | mqtt = new CloudIoTCoreMqtt(mqttClient, netClient, device);
114 | mqtt->startMQTT();
115 | }
--------------------------------------------------------------------------------
/examples/Esp32-lwmqtt/ciotc_config.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // This file contains your configuration used to connect to Cloud IoT Core
16 |
17 | // Wifi network details.
18 | const char *ssid = "SSID";
19 | const char *password = "PASSWORD";
20 |
21 | // Cloud iot details.
22 | const char *project_id = "project-id";
23 | const char *location = "us-central1";
24 | const char *registry_id = "my-registry";
25 | const char *device_id = "my-esp32-device";
26 |
27 | // Configuration for NTP
28 | const char* ntp_primary = "pool.ntp.org";
29 | const char* ntp_secondary = "time.nist.gov";
30 |
31 | #ifndef LED_BUILTIN
32 | #define LED_BUILTIN 13
33 | #endif
34 |
35 | // To get the private key run (where private-key.pem is the ec private key
36 | // used to create the certificate uploaded to google cloud iot):
37 | // openssl ec -in -noout -text
38 | // and copy priv: part.
39 | // The key length should be exactly the same as the key length bellow (32 pairs
40 | // of hex digits). If it's bigger and it starts with "00:" delete the "00:". If
41 | // it's smaller add "00:" to the start. If it's too big or too small something
42 | // is probably wrong with your key.
43 | const char *private_key_str =
44 | "6e:b8:17:35:c7:fc:6b:d7:a9:cb:cb:49:7f:a0:67:"
45 | "63:38:b0:90:57:57:e0:c0:9a:e8:6f:06:0c:d9:ee:"
46 | "31:41";
47 |
48 | // Time (seconds) to expire token += 20 minutes for drift
49 | const int jwt_exp_secs = 60*20; // Maximum 24H (3600*24)
50 |
51 | // To get the certificate for your region run:
52 | // openssl s_client -showcerts -connect mqtt.googleapis.com:8883
53 | // for standard mqtt or for LTS:
54 | // openssl s_client -showcerts -connect mqtt.2030.ltsapis.goog:8883
55 | // Copy the certificate (all lines between and including ---BEGIN CERTIFICATE---
56 | // and --END CERTIFICATE--) to root.cert and put here on the root_cert variable.
57 |
58 | // Alternatively, get Google's minimal root CA set for mqtt.2030.ltsapis.goog.
59 | // https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#downloading_mqtt_server_certificates
60 | // wget https://pki.goog/gtsltsr/gtsltsr.crt
61 | // openssl x509 -inform DER -in gtsltsr.crt -out primary.pem -text
62 |
63 | const char *root_cert =
64 | "-----BEGIN CERTIFICATE-----\n"
65 | "MIIBxTCCAWugAwIBAgINAfD3nVndblD3QnNxUDAKBggqhkjOPQQDAjBEMQswCQYD\n"
66 | "VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzERMA8G\n"
67 | "A1UEAxMIR1RTIExUU1IwHhcNMTgxMTAxMDAwMDQyWhcNNDIxMTAxMDAwMDQyWjBE\n"
68 | "MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\n"
69 | "QzERMA8GA1UEAxMIR1RTIExUU1IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN\n"
70 | "8YyO2u+yCQoZdwAkUNv5c3dokfULfrA6QJgFV2XMuENtQZIG5HUOS6jFn8f0ySlV\n"
71 | "eORCxqFyjDJyRn86d+Iko0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw\n"
72 | "AwEB/zAdBgNVHQ4EFgQUPv7/zFLrvzQ+PfNA0OQlsV+4u1IwCgYIKoZIzj0EAwID\n"
73 | "SAAwRQIhAPKuf/VtBHqGw3TUwUIq7TfaExp3bH7bjCBmVXJupT9FAiBr0SmCtsuk\n"
74 | "miGgpajjf/gFigGM34F9021bCWs1MbL0SA==\n"
75 | "-----END CERTIFICATE-----\n";
76 |
77 | // In case we ever need extra topics
78 | const int ex_num_topics = 0;
79 | const char* ex_topics[ex_num_topics];
80 | //const int ex_num_topics = 1;
81 | //const char* ex_topics[ex_num_topics] = {
82 | // "/devices/my-device/tbd/#"
83 | //};
84 |
--------------------------------------------------------------------------------
/examples/Esp32-lwmqtt/esp32-mqtt.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // This file contains static methods for API requests using Wifi / MQTT
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 |
22 | #include
23 | #include
24 | #include "ciotc_config.h" // Update this file with your configuration
25 |
26 | // !!REPLACEME!!
27 | // The MQTT callback function for commands and configuration updates
28 | // Place your message handler code here.
29 | void messageReceived(String &topic, String &payload){
30 | Serial.println("incoming: " + topic + " - " + payload);
31 | }
32 | ///////////////////////////////
33 |
34 | // Initialize WiFi and MQTT for this board
35 | WiFiClientSecure *netClient;
36 | CloudIoTCoreDevice *device;
37 | CloudIoTCoreMqtt *mqtt;
38 | MQTTClient *mqttClient;
39 | unsigned long iat = 0;
40 | String jwt;
41 |
42 | ///////////////////////////////
43 | // Helpers specific to this board
44 | ///////////////////////////////
45 | String getDefaultSensor(){
46 | return "Wifi: " + String(WiFi.RSSI()) + "db";
47 | }
48 |
49 | String getJwt(){
50 | iat = time(nullptr);
51 | Serial.println("Refreshing JWT");
52 | jwt = device->createJWT(iat, jwt_exp_secs);
53 | return jwt;
54 | }
55 |
56 | void setupWifi(){
57 | Serial.println("Starting wifi");
58 |
59 | WiFi.mode(WIFI_STA);
60 | // WiFi.setSleep(false); // May help with disconnect? Seems to have been removed from WiFi
61 | WiFi.begin(ssid, password);
62 | Serial.println("Connecting to WiFi");
63 | while (WiFi.status() != WL_CONNECTED){
64 | delay(100);
65 | }
66 |
67 | configTime(0, 0, ntp_primary, ntp_secondary);
68 | Serial.println("Waiting on time sync...");
69 | while (time(nullptr) < 1510644967){
70 | delay(10);
71 | }
72 | }
73 |
74 | void connectWifi(){
75 | Serial.print("checking wifi...");
76 | while (WiFi.status() != WL_CONNECTED){
77 | Serial.print(".");
78 | delay(1000);
79 | }
80 | }
81 |
82 | ///////////////////////////////
83 | // Orchestrates various methods from preceeding code.
84 | ///////////////////////////////
85 | bool publishTelemetry(String data){
86 | return mqtt->publishTelemetry(data);
87 | }
88 |
89 | bool publishTelemetry(const char *data, int length){
90 | return mqtt->publishTelemetry(data, length);
91 | }
92 |
93 | bool publishTelemetry(String subfolder, String data){
94 | return mqtt->publishTelemetry(subfolder, data);
95 | }
96 |
97 | bool publishTelemetry(String subfolder, const char *data, int length){
98 | return mqtt->publishTelemetry(subfolder, data, length);
99 | }
100 |
101 | void connect(){
102 | connectWifi();
103 | mqtt->mqttConnect();
104 | }
105 |
106 | void setupCloudIoT(){
107 | device = new CloudIoTCoreDevice(
108 | project_id, location, registry_id, device_id,
109 | private_key_str);
110 |
111 | setupWifi();
112 | netClient = new WiFiClientSecure();
113 | netClient->setCACert(root_cert);
114 | mqttClient = new MQTTClient(512);
115 | mqttClient->setOptions(180, true, 1000); // keepAlive, cleanSession, timeout
116 | mqtt = new CloudIoTCoreMqtt(mqttClient, netClient, device);
117 | mqtt->setUseLts(true);
118 | mqtt->startMQTT();
119 | }
--------------------------------------------------------------------------------
/examples/Esp8266-lwmqtt/ciotc_config.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // This file contains your configuration used to connect to Cloud IoT Core
16 |
17 | // WIFI
18 | const char* ssid = "SSID";
19 | const char* password = "PASSWORD";
20 |
21 | // Cloud iot details.
22 | const char* project_id = "project-id";
23 | const char* location = "us-central1";
24 | const char* registry_id = "my-registry";
25 | const char* device_id = "my-device";
26 |
27 | // Configuration for NTP
28 | const char* ntp_primary = "time.google.com";
29 | const char* ntp_secondary = "pool.ntp.org";
30 |
31 | // To get the private key run (where private-key.pem is the ec private key
32 | // used to create the certificate uploaded to google cloud iot):
33 | // openssl ec -in -noout -text
34 | // and copy priv: part.
35 | // The key length should be exactly the same as the key length bellow (32 pairs
36 | // of hex digits). If it's bigger and it starts with "00:" delete the "00:". If
37 | // it's smaller add "00:" to the start. If it's too big or too small something
38 | // is probably wrong with your key.
39 | const unsigned char private_key[] = {
40 | 0x5a, 0x2e, 0x06, 0xb5, 0xc1, 0xf2, 0x9c, 0xb3, 0x77, 0xb2, 0x89, 0xf5, 0x29, 0x29, 0x93,
41 | 0x07, 0xfd, 0xed, 0x22, 0x0d, 0x03, 0x2b, 0xa6, 0xb1, 0xb6, 0x04, 0x0b, 0xd5, 0x9b, 0x49,
42 | 0x7d, 0xca};
43 |
44 | // Time (seconds) to expire token += 20 minutes for drift
45 | const int jwt_exp_secs = 3600; // Maximum 24H (3600*24)
46 |
47 | // Certificates for SSL on the LTS server
48 | const char* primary_ca = "-----BEGIN CERTIFICATE-----\n"
49 | "MIIBxTCCAWugAwIBAgINAfD3nVndblD3QnNxUDAKBggqhkjOPQQDAjBEMQswCQYD\n"
50 | "VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzERMA8G\n"
51 | "A1UEAxMIR1RTIExUU1IwHhcNMTgxMTAxMDAwMDQyWhcNNDIxMTAxMDAwMDQyWjBE\n"
52 | "MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\n"
53 | "QzERMA8GA1UEAxMIR1RTIExUU1IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN\n"
54 | "8YyO2u+yCQoZdwAkUNv5c3dokfULfrA6QJgFV2XMuENtQZIG5HUOS6jFn8f0ySlV\n"
55 | "eORCxqFyjDJyRn86d+Iko0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw\n"
56 | "AwEB/zAdBgNVHQ4EFgQUPv7/zFLrvzQ+PfNA0OQlsV+4u1IwCgYIKoZIzj0EAwID\n"
57 | "SAAwRQIhAPKuf/VtBHqGw3TUwUIq7TfaExp3bH7bjCBmVXJupT9FAiBr0SmCtsuk\n"
58 | "miGgpajjf/gFigGM34F9021bCWs1MbL0SA==\n"
59 | "-----END CERTIFICATE-----\n";
60 |
61 | const char* backup_ca = "-----BEGIN CERTIFICATE-----\n"
62 | "MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk\n"
63 | "MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH\n"
64 | "bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX\n"
65 | "DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD\n"
66 | "QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu\n"
67 | "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ\n"
68 | "FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw\n"
69 | "DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F\n"
70 | "uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX\n"
71 | "kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs\n"
72 | "ewv4n4Q=\n"
73 | "-----END CERTIFICATE-----\n";
74 |
75 | // In case we ever need extra topics
76 | const int ex_num_topics = 0;
77 | const char* ex_topics[ex_num_topics];
78 | //const int ex_num_topics = 1;
79 | //const char* ex_topics[ex_num_topics] = {
80 | // "/devices/my-device/tbd/#"
81 | //};
82 |
--------------------------------------------------------------------------------
/examples/complex/esp32/Gateway/Esp32-delegate/Esp32-delegate.ino:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2020 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | #if defined(ESP8266) or defined(ARDUINO_SAMD_MKR1000)
16 | #define __SKIP_ESP32__
17 | #endif
18 |
19 | #if defined(ESP32)
20 | #define __ESP32_MQTT__
21 | #endif
22 |
23 | #ifdef __SKIP_ESP32__
24 |
25 | #include
26 |
27 | void setup(){
28 | Serial.begin(115200);
29 | }
30 |
31 | void loop(){
32 | Serial.println("Hello World");
33 | }
34 |
35 | #endif
36 |
37 | #ifdef __ESP32_MQTT__
38 |
39 | #include "BluetoothSerial.h"
40 |
41 | BluetoothSerial SerialBT;
42 |
43 | const String DeviceID = "my-esp-device";
44 |
45 | #ifdef __cplusplus
46 | extern "C" {
47 | #endif
48 | uint8_t temprature_sens_read();
49 | #ifdef __cplusplus
50 | }
51 | #endif
52 |
53 |
54 | typedef struct __attribute__((packed)) SERIALBTMSG{
55 | String deviceid;
56 | String command;
57 | String payload;
58 | String type;
59 | } btMsg;
60 |
61 | btMsg incomingMsg;
62 |
63 | String input;
64 |
65 |
66 | // Processes commands sent by the Gateway device that correspond to messages from
67 | // Google Cloud IoT Core. These messages can be 'configuration' for Cloud configuration
68 | // messages, 'event' for requests to transmit telemetry events from the delegate device,
69 | // and 'state' for when the gateway is requesting a state update from the delegate device.
70 | void handleGatewayCommand() {
71 | if (incomingMsg.deviceid != DeviceID) {
72 | Serial.println("Connected to wrong Device;");
73 | return;
74 | }
75 |
76 | if (incomingMsg.command == "configuration") {
77 | // Write your code to handle configurations
78 | Serial.println(incomingMsg.payload);
79 | } else if (incomingMsg.command == "event") {
80 | if (incomingMsg.payload == "get temperature") {
81 | SerialBT.println("type:Command");
82 | SerialBT.println("data:" + String((temprature_sens_read() - 32) / 1.8) + " C;");
83 | Serial.println("Sent Data");
84 | } else {
85 | Serial.print("Couldn't Find payload");
86 | }
87 | } else if (incomingMsg.command == "state") {
88 | if (incomingMsg.payload == "get state") {
89 | SerialBT.println("type:Command");
90 | SerialBT.println("data: Device on;");
91 | Serial.println("Sent Data");
92 | }
93 | }
94 | }
95 |
96 |
97 | void parseInput(String in) {
98 | int x = 0;
99 | char strArray[in.length()+1];
100 | in.toCharArray(strArray,in.length()+1);
101 | char* pars = strtok (strArray,",");
102 | char* msgArray[3];
103 | while (pars != NULL) {
104 | msgArray[x] = pars;
105 | x++;
106 | pars = strtok (NULL,",");
107 | }
108 |
109 | incomingMsg.deviceid = String(msgArray[0]);
110 | incomingMsg.command = String(msgArray[1]);
111 | incomingMsg.payload = String(msgArray[2]);
112 |
113 | Serial.println(incomingMsg.payload);
114 |
115 | handleGatewayCommand();
116 |
117 | delay(1000);
118 | }
119 |
120 |
121 | void setup() {
122 | Serial.begin(115200);
123 | SerialBT.begin(DeviceID); //Bluetooth device name
124 | Serial.println("The device started, now you can pair it with bluetooth!");
125 | }
126 |
127 |
128 | void loop() {
129 | if (Serial.available()) {
130 | SerialBT.write(Serial.read());
131 | }
132 | if (SerialBT.available()) {
133 | input = (SerialBT.readStringUntil(';'));
134 | Serial.println(input);
135 | parseInput(input);
136 | ESP.restart();
137 | }
138 | }
139 | #endif
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/Animations/3973-ripples.json:
--------------------------------------------------------------------------------
1 | {"v":"5.4.2","fr":29.9700012207031,"ip":0,"op":70.0000028511585,"w":540,"h":405,"nm":"Comp 2","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"core","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[270,202.5,0],"ix":2},"a":{"a":0,"k":[-30.082,-0.082,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":0,"s":[70,70,100],"e":[70,70,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":20,"s":[70,70,100],"e":[90,90,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":30,"s":[90,90,100],"e":[70,70,100]},{"t":70.0000028511585}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[200,200],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.113725490868,0.749019622803,0.450980395079,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.082,-0.082],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":103.000004195276,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"small ripple","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p833_1_0p333_0"],"t":17,"s":[0],"e":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":27,"s":[100],"e":[0]},{"t":60.0000024438501}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[270,202.5,0],"ix":2},"a":{"a":0,"k":[-30.082,-0.082,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":17,"s":[50,50,100],"e":[120,120,100]},{"t":60.0000024438501}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[300,300],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.113725490868,0.749019622803,0.450980395079,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.082,-0.082],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":103.000004195276,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"large ripple","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"n":["0p833_1_0p167_0"],"t":10,"s":[0],"e":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":20,"s":[100],"e":[0]},{"t":50.0000020365418}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[270,202.5,0],"ix":2},"a":{"a":0,"k":[-30.082,-0.082,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":10,"s":[0,0,100],"e":[130,130,100]},{"t":40.0000016292334}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[300,300],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.113725490868,0.749019622803,0.450980395079,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.082,-0.082],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":103.000004195276,"st":0,"bm":0}],"markers":[]}
--------------------------------------------------------------------------------
/examples/complex/esp32/camera/ciotc_config.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2019 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // This file contains your configuration used to connect to Cloud IoT Core
16 |
17 | // Wifi network details.
18 | const char *ssid = "SSID";
19 | const char *password = "PASSWORD";
20 |
21 | // Cloud iot details.
22 | const char *project_id = "project-id";
23 | const char *location = "us-central1";
24 | const char *registry_id = "my-registry";
25 | const char *device_id = "my-esp32-device";
26 |
27 | // Configuration for NTP
28 | const char* ntp_primary = "pool.ntp.org";
29 | const char* ntp_secondary = "time.nist.gov";
30 |
31 | #ifndef LED_BUILTIN
32 | #define LED_BUILTIN 13
33 | #endif
34 |
35 |
36 |
37 | // To get the private key run (where private-key.pem is the ec private key
38 | // used to create the certificate uploaded to google cloud iot):
39 | // openssl ec -in -noout -text
40 | // and copy priv: part.
41 | // The key length should be exactly the same as the key length bellow (32 pairs
42 | // of hex digits). If it's bigger and it starts with "00:" delete the "00:". If
43 | // it's smaller add "00:" to the start. If it's too big or too small something
44 | // is probably wrong with your key.
45 | const char *private_key_str =
46 | "6e:b8:17:35:c7:fc:6b:d7:a9:cb:cb:49:7f:a0:67:"
47 | "63:38:b0:90:57:57:e0:c0:9a:e8:6f:06:0c:d9:ee:"
48 | "31:41";
49 |
50 | // Time (seconds) to expire token += 20 minutes for drift
51 | const int jwt_exp_secs = 60*20; // Maximum 24H (3600*24)
52 |
53 | // To get the certificate for your region run:
54 | // openssl s_client -showcerts -connect mqtt.googleapis.com:8883
55 | // Copy the certificate (all lines between and including ---BEGIN CERTIFICATE---
56 | // and --END CERTIFICATE--) to root.cert and put here on the root_cert variable.
57 |
58 | const char *root_cert =
59 | "-----BEGIN CERTIFICATE-----\n"
60 | "MIIEXDCCA0SgAwIBAgINAeOpMBz8cgY4P5pTHTANBgkqhkiG9w0BAQsFADBMMSAw\n"
61 | "HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFs\n"
62 | "U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xNzA2MTUwMDAwNDJaFw0yMTEy\n"
63 | "MTUwMDAwNDJaMFQxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVHb29nbGUgVHJ1c3Qg\n"
64 | "U2VydmljZXMxJTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzMw\n"
65 | "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKUkvqHv/OJGuo2nIYaNVW\n"
66 | "XQ5IWi01CXZaz6TIHLGp/lOJ+600/4hbn7vn6AAB3DVzdQOts7G5pH0rJnnOFUAK\n"
67 | "71G4nzKMfHCGUksW/mona+Y2emJQ2N+aicwJKetPKRSIgAuPOB6Aahh8Hb2XO3h9\n"
68 | "RUk2T0HNouB2VzxoMXlkyW7XUR5mw6JkLHnA52XDVoRTWkNty5oCINLvGmnRsJ1z\n"
69 | "ouAqYGVQMc/7sy+/EYhALrVJEA8KbtyX+r8snwU5C1hUrwaW6MWOARa8qBpNQcWT\n"
70 | "kaIeoYvy/sGIJEmjR0vFEwHdp1cSaWIr6/4g72n7OqXwfinu7ZYW97EfoOSQJeAz\n"
71 | "AgMBAAGjggEzMIIBLzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH\n"
72 | "AwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHfCuFCa\n"
73 | "Z3Z2sS3ChtCDoH6mfrpLMB8GA1UdIwQYMBaAFJviB1dnHB7AagbeWbSaLd/cGYYu\n"
74 | "MDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AucGtpLmdv\n"
75 | "b2cvZ3NyMjAyBgNVHR8EKzApMCegJaAjhiFodHRwOi8vY3JsLnBraS5nb29nL2dz\n"
76 | "cjIvZ3NyMi5jcmwwPwYDVR0gBDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYc\n"
77 | "aHR0cHM6Ly9wa2kuZ29vZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEA\n"
78 | "HLeJluRT7bvs26gyAZ8so81trUISd7O45skDUmAge1cnxhG1P2cNmSxbWsoiCt2e\n"
79 | "ux9LSD+PAj2LIYRFHW31/6xoic1k4tbWXkDCjir37xTTNqRAMPUyFRWSdvt+nlPq\n"
80 | "wnb8Oa2I/maSJukcxDjNSfpDh/Bd1lZNgdd/8cLdsE3+wypufJ9uXO1iQpnh9zbu\n"
81 | "FIwsIONGl1p3A8CgxkqI/UAih3JaGOqcpcdaCIzkBaR9uYQ1X4k2Vg5APRLouzVy\n"
82 | "7a8IVk6wuy6pm+T7HT4LY8ibS5FEZlfAFLSW8NwsVz9SBK2Vqn1N0PIMn5xA6NZV\n"
83 | "c7o835DLAFshEWfC7TIe3g==\n"
84 | "-----END CERTIFICATE-----\n";
85 |
--------------------------------------------------------------------------------
/examples/universal-lwmqtt/ciotc_config.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2019 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // This file contains your configuration used to connect to Cloud IoT Core
16 |
17 | // Important!
18 | // TODO(you): Install root certificate to verify tls connection as described
19 | // in https://www.hackster.io/arichetta/add-ssl-certificates-to-mkr1000-93c89d
20 |
21 | // Wifi network details.
22 | const char* ssid = "YOUR_WIFI_SSID";
23 | const char* password = "YOUR_WIFI_PASS";
24 |
25 | // Cloud iot details.
26 | const char* project_id = "YOUR_PROJECT_ID";
27 | const char* location = "us-central1";
28 | const char* registry_id = "YOUR_REGISTRY_ID";
29 | const char* device_id = "YOUR_DEVICE_ID";
30 |
31 | // Configuration for NTP
32 | const char* ntp_primary = "pool.ntp.org";
33 | const char* ntp_secondary = "time.nist.gov";
34 |
35 | #ifndef LED_BUILTIN
36 | #define LED_BUILTIN 13
37 | #endif
38 |
39 | // To get the private key run (where private-key.pem is the ec private key
40 | // used to create the certificate uploaded to google cloud iot):
41 | // openssl ec -in -noout -text
42 | // and copy priv: part.
43 | // The key length should be exactly the same as the key length bellow (32 pairs
44 | // of hex digits). If it's bigger and it starts with "00:" delete the "00:". If
45 | // it's smaller add "00:" to the start. If it's too big or too small something
46 | // is probably wrong with your key.
47 | const char* private_key_str =
48 | "42:42:42:42:42:42:42:42:42:e3:51:e9:83:4a:f9:"
49 | "42:42:42:16:42:42:c0:77:0d:47:54:62:92:11:a6:"
50 | "42:42";
51 |
52 | // Time (seconds) to expire token += 20 minutes for drift
53 | const int jwt_exp_secs = 3600; // Maximum 24H (3600*24)
54 |
55 | // Use the root certificate to verify tls connection rather than
56 | // using a fingerprint.
57 | const char* primary_ca = "-----BEGIN CERTIFICATE-----\n"
58 | "MIIBxTCCAWugAwIBAgINAfD3nVndblD3QnNxUDAKBggqhkjOPQQDAjBEMQswCQYD\n"
59 | "VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzERMA8G\n"
60 | "A1UEAxMIR1RTIExUU1IwHhcNMTgxMTAxMDAwMDQyWhcNNDIxMTAxMDAwMDQyWjBE\n"
61 | "MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\n"
62 | "QzERMA8GA1UEAxMIR1RTIExUU1IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN\n"
63 | "8YyO2u+yCQoZdwAkUNv5c3dokfULfrA6QJgFV2XMuENtQZIG5HUOS6jFn8f0ySlV\n"
64 | "eORCxqFyjDJyRn86d+Iko0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw\n"
65 | "AwEB/zAdBgNVHQ4EFgQUPv7/zFLrvzQ+PfNA0OQlsV+4u1IwCgYIKoZIzj0EAwID\n"
66 | "SAAwRQIhAPKuf/VtBHqGw3TUwUIq7TfaExp3bH7bjCBmVXJupT9FAiBr0SmCtsuk\n"
67 | "miGgpajjf/gFigGM34F9021bCWs1MbL0SA==\n"
68 | "-----END CERTIFICATE-----\n";
69 |
70 | const char* backup_ca = "-----BEGIN CERTIFICATE-----\n"
71 | "MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk\n"
72 | "MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH\n"
73 | "bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX\n"
74 | "DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD\n"
75 | "QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu\n"
76 | "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ\n"
77 | "FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw\n"
78 | "DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F\n"
79 | "uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX\n"
80 | "kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs\n"
81 | "ewv4n4Q=\n"
82 | "-----END CERTIFICATE-----\n";
83 |
84 | // In case we ever need extra topics
85 | const int ex_num_topics = 0;
86 | const char* ex_topics[ex_num_topics];
87 | //const int ex_num_topics = 1;
88 | //const char* ex_topics[ex_num_topics] = {
89 | // "/devices/my-device/tbd/#"
90 | //};
91 |
--------------------------------------------------------------------------------
/src/jwt.cpp:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 |
16 | #include
17 |
18 | #include "crypto/ecdsa.h"
19 | #include "crypto/nn.h"
20 | #include "crypto/sha256.h"
21 | #include "jwt.h"
22 |
23 | // base64_encode copied from https://github.com/ReneNyffenegger/cpp-base64
24 | static const char base64_chars[] =
25 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
26 | "abcdefghijklmnopqrstuvwxyz"
27 | "0123456789-_";
28 |
29 | String base64_encode(const unsigned char *bytes_to_encode,
30 | unsigned int in_len) {
31 | String ret;
32 | int i = 0;
33 | int j = 0;
34 | unsigned char char_array_3[3];
35 | unsigned char char_array_4[4];
36 |
37 | while (in_len--) {
38 | char_array_3[i++] = *(bytes_to_encode++);
39 | if (i == 3) {
40 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
41 | char_array_4[1] =
42 | ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
43 | char_array_4[2] =
44 | ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
45 | char_array_4[3] = char_array_3[2] & 0x3f;
46 |
47 | for (i = 0; (i < 4); i++) {
48 | ret += base64_chars[char_array_4[i]];
49 | }
50 | i = 0;
51 | }
52 | }
53 |
54 | if (i) {
55 | for (j = i; j < 3; j++) {
56 | char_array_3[j] = '\0';
57 | }
58 |
59 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
60 | char_array_4[1] =
61 | ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
62 | char_array_4[2] =
63 | ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
64 | char_array_4[3] = char_array_3[2] & 0x3f;
65 |
66 | for (j = 0; (j < i + 1); j++) {
67 | ret += base64_chars[char_array_4[j]];
68 | }
69 | }
70 |
71 | return ret;
72 | }
73 |
74 | String base64_encode(String str) {
75 | return base64_encode((const unsigned char *)str.c_str(), str.length());
76 | }
77 |
78 | // Get base64 signature string from the signature_r and signature_s ecdsa
79 | // signature.
80 | String MakeBase64Signature(NN_DIGIT *signature_r, NN_DIGIT *signature_s) {
81 | unsigned char signature[64];
82 | NN_Encode(signature, (NUMWORDS - 1) * NN_DIGIT_LEN, signature_r,
83 | (NN_UINT)(NUMWORDS - 1));
84 | NN_Encode(signature + (NUMWORDS - 1) * NN_DIGIT_LEN,
85 | (NUMWORDS - 1) * NN_DIGIT_LEN, signature_s,
86 | (NN_UINT)(NUMWORDS - 1));
87 |
88 | return base64_encode(signature, 64);
89 | }
90 |
91 | String CreateJwt(const char *project_id, long long int time, NN_DIGIT *priv_key, int jwt_exp_secs) {
92 | ecc_init();
93 | // Making jwt token json
94 |
95 | // payload
96 | String payload = String("{\"iat\":") + (int) time
97 | + ",\"exp\":" + (int) (time + jwt_exp_secs)
98 | + ",\"aud\":\"" + project_id + "\"}";
99 |
100 | // header: base64_encode("{\"alg\":\"ES256\",\"typ\":\"JWT\"}") + "."
101 | String header_payload_base64 =
102 | "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9." + base64_encode(payload);
103 |
104 | Sha256 sha256Instance;
105 | sha256Instance.update((const unsigned char *)header_payload_base64.c_str(), header_payload_base64.length());
106 | unsigned char sha256[SHA256_DIGEST_LENGTH];
107 | sha256Instance.final(sha256);
108 |
109 | // Signing sha with ec key. Bellow is the ec private key.
110 | point_t pub_key;
111 | ecc_gen_pub_key(priv_key, &pub_key);
112 |
113 | ecdsa_init(&pub_key);
114 |
115 | NN_DIGIT signature_r[NUMWORDS], signature_s[NUMWORDS];
116 | ecdsa_sign((uint8_t *)sha256, signature_r, signature_s, priv_key);
117 |
118 | return header_payload_base64 + "." +
119 | MakeBase64Signature(signature_r, signature_s);
120 | }
121 |
122 | String CreateJwt(String &project_id, long long int time, NN_DIGIT *priv_key, int jwt_exp_secs) {
123 | return CreateJwt(project_id.c_str(), time, priv_key, jwt_exp_secs);
124 | }
125 |
126 | String CreateJwt(String &project_id, long long int time, NN_DIGIT *priv_key) {
127 | return CreateJwt(project_id, time, priv_key, 3600); // one hour default
128 | }
129 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/SwiftUIClient.swift:
--------------------------------------------------------------------------------
1 | //**************************************************************************
2 | // Copyright 2020 Google
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // 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
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | // *****************************************************************************/
15 |
16 | import SwiftUI
17 |
18 | class contentViewDelegate : ObservableObject {
19 | @Published var toDisconnect: Bool = false
20 | }
21 |
22 |
23 | struct SwiftUIClient: View {
24 |
25 | @ObservedObject var delegate: contentViewDelegate
26 | @ObservedObject var viewController: IoTBLEView
27 |
28 | @State var tempMQTT: String = "MQTT Terminal"
29 | @State var tempData: String = "Temp Data"
30 | @State var connectedSate : Bool = false
31 | @State var filename : String = "3973-ripples"
32 | @State var type:String = "Disconnect from Cloud"
33 |
34 |
35 | var body: some View {
36 |
37 | ZStack {
38 |
39 | Group {
40 | Rectangle()
41 | .fill(Color("Background")).frame(maxWidth:.infinity, maxHeight:.infinity).edgesIgnoringSafeArea(.all)
42 |
43 | RoundedRectangle(cornerRadius: 20)
44 | .fill(Color("Background"))
45 | .frame(width:300,height: 200)
46 | .shadow(color: Color("LightShadow"), radius: 8, x: -8, y: -8)
47 | .shadow(color: Color("DarkShadow"), radius: 8, x: 8, y: 8)
48 | .offset(x: 0, y: -200)
49 |
50 | RoundedRectangle(cornerRadius: 20)
51 | .fill(Color("Background"))
52 | .frame(width:300,height: 200)
53 | .shadow(color: Color("LightShadow"), radius: 8, x: -8, y: -8)
54 | .shadow(color: Color("DarkShadow"), radius: 8, x: 8, y: 8)
55 | .offset(x: 0, y: 60)
56 |
57 | Text(viewController.command)
58 | .offset(x: 0, y: -200)
59 | .frame(width:280,height: 180)
60 | .foregroundColor(Color("textcolor"))
61 |
62 | Text(viewController.sensorData)
63 | .frame(width:280,height: 180)
64 | .offset(x: 0, y: 60)
65 | .foregroundColor(Color("textcolor"))
66 | }
67 |
68 | Group{
69 | Image("IoTCore").resizable().frame(width: 50, height: 50).position(x: 50, y: 25)
70 | Text("MQTT Client").foregroundColor(Color("textcolor")).font(.headline).position(x: 140, y: 16)
71 | Text("Gateway Device").foregroundColor(Color("textcolor")).font(.subheadline).position(x: 145, y: 35)
72 | }
73 |
74 | Group {
75 | if(viewController.command == ""){
76 | LottieView(filename:"3517-growing-circle").frame(width: 50, height: 50).position(x: 350, y: 25)
77 | } else {
78 | LottieView(filename:filename).frame(width: 50, height: 50).position(x: 350, y: 25)
79 | }
80 |
81 | Button(action: {
82 | // your action here
83 | if(self.delegate.toDisconnect == false){
84 | self.viewController.command = ""
85 | self.delegate.toDisconnect = true
86 | self.self.type = "Connect to Cloud"
87 |
88 | }else{
89 | self.delegate.toDisconnect = false
90 | self.self.type = "Disconnect Cloud"
91 | }
92 |
93 | }) {
94 | Text(self.type)
95 | }.frame(width: 180, height: 25)
96 | .padding()
97 | .foregroundColor(.white)
98 | .background(Color("Button"))
99 | .cornerRadius(40)
100 | .padding(.horizontal, 50).position(x: 205, y: 680)
101 | }
102 | }
103 | }
104 | }
105 |
106 |
107 | struct SwiftUIObservingUIKit_Previews: PreviewProvider {
108 | static var previews: some View {
109 | SwiftUIClient(delegate: contentViewDelegate(), viewController: IoTBLEView())
110 | }
111 | }
112 |
113 |
--------------------------------------------------------------------------------
/examples/complex/esp32/Gateway/Esp32-gateway/ciotc_config.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2020 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // This file contains your configuration used to connect to Cloud IoT Core
16 |
17 | // Wifi network details.
18 | const char *ssid = "SSID";
19 | const char *password = "PASSWORD";
20 |
21 | // Cloud iot details.
22 | const char *project_id = "project-id";
23 | const char *location = "us-central1";
24 | const char *registry_id = "my-registry";
25 | const char *device_id = "my-esp32-gateway";
26 |
27 | // Cloud iot delegate device details.
28 | const String delegate_device_id[] = {"my-esp32-device1","my-esp32-device2"};
29 |
30 | // Configuration for NTP
31 | const char* ntp_primary = "pool.ntp.org";
32 | const char* ntp_secondary = "time.nist.gov";
33 |
34 | #ifndef LED_BUILTIN
35 | #define LED_BUILTIN 13
36 | #endif
37 |
38 | // To get the private key run (where private-key.pem is the ec private key
39 | // used to create the certificate uploaded to google cloud iot):
40 | // openssl ec -in -noout -text
41 | // and copy priv: part.
42 | // The key length should be exactly the same as the key length bellow (32 pairs
43 | // of hex digits). If it's bigger and it starts with "00:" delete the "00:". If
44 | // it's smaller add "00:" to the start. If it's too big or too small something
45 | // is probably wrong with your key.
46 | const char *private_key_str =
47 | "6e:b8:17:35:c7:fc:6b:d7:a9:cb:cb:49:7f:a0:67:"
48 | "63:38:b0:90:57:57:e0:c0:9a:e8:6f:06:0c:d9:ee:"
49 | "31:41";
50 |
51 |
52 | // Time (seconds) to expire token += 20 minutes for drift
53 | const int jwt_exp_secs = 3600; // Maximum 24H (3600*24)
54 |
55 | // To get the certificate for your region run:
56 | // openssl s_client -showcerts -connect mqtt.googleapis.com:8883
57 | // for standard mqtt or for LTS:
58 | // openssl s_client -showcerts -connect mqtt.2030.ltsapis.goog:8883
59 | // Copy the certificate (all lines between and including ---BEGIN CERTIFICATE---
60 | // and --END CERTIFICATE--) to root.cert and put here on the root_cert variable.
61 |
62 | const char *root_cert =
63 | "-----BEGIN CERTIFICATE-----\n"
64 | "MIIErjCCA5agAwIBAgIQW+5sTJWKajts11BgHkBRwjANBgkqhkiG9w0BAQsFADBU\n"
65 | "MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMSUw\n"
66 | "IwYDVQQDExxHb29nbGUgSW50ZXJuZXQgQXV0aG9yaXR5IEczMB4XDTE5MDYxMTEy\n"
67 | "MzE1OVoXDTE5MDkwMzEyMjAwMFowbTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh\n"
68 | "bGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzARBgNVBAoMCkdvb2ds\n"
69 | "ZSBMTEMxHDAaBgNVBAMME21xdHQuZ29vZ2xlYXBpcy5jb20wggEiMA0GCSqGSIb3\n"
70 | "DQEBAQUAA4IBDwAwggEKAoIBAQDHuQUoDZWl2155WvaQ9AmhTRNC+mHassokdQK7\n"
71 | "NxkZVZfrS8EhRkZop6SJGHdvozBP3Ko3g1MgGIZFzqb5fRohkRKB6mteHHi/W7Uo\n"
72 | "7d8+wuTTz3llUZ2gHF/hrXFJfztwnaZub/KB+fXwSqWgMyo1EBme4ULV0rQZGFu6\n"
73 | "7U38HK+mFRbeJkh1SDOureI2dxkC4ACGiqWfX/vSyzpZkWGRuxK2F5cnBHqRbcKs\n"
74 | "OfmYyUuxZjGah+fC5ePgDbAntLUuYNppkdgT8yt/13ae/V7+rRhKOZC4q76HBEaQ\n"
75 | "4Wn5UC+ShVaAGuo7BtfoIFSyZi8/DU2eTQcHWewIXU6V5InhAgMBAAGjggFhMIIB\n"
76 | "XTATBgNVHSUEDDAKBggrBgEFBQcDATA4BgNVHREEMTAvghNtcXR0Lmdvb2dsZWFw\n"
77 | "aXMuY29tghhtcXR0LW10bHMuZ29vZ2xlYXBpcy5jb20waAYIKwYBBQUHAQEEXDBa\n"
78 | "MC0GCCsGAQUFBzAChiFodHRwOi8vcGtpLmdvb2cvZ3NyMi9HVFNHSUFHMy5jcnQw\n"
79 | "KQYIKwYBBQUHMAGGHWh0dHA6Ly9vY3NwLnBraS5nb29nL0dUU0dJQUczMB0GA1Ud\n"
80 | "DgQWBBSKWpFfG/yH1dkkJT05y/ZnRm/M4DAMBgNVHRMBAf8EAjAAMB8GA1UdIwQY\n"
81 | "MBaAFHfCuFCaZ3Z2sS3ChtCDoH6mfrpLMCEGA1UdIAQaMBgwDAYKKwYBBAHWeQIF\n"
82 | "AzAIBgZngQwBAgIwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDovL2NybC5wa2kuZ29v\n"
83 | "Zy9HVFNHSUFHMy5jcmwwDQYJKoZIhvcNAQELBQADggEBAKMoXHxmLI1oKnraV0tL\n"
84 | "NzznlVnle4ljS/pqNI8LUM4/5QqD3qGqnI4fBxX1l+WByCitbTiNvL2KRNi9xau5\n"
85 | "oqvsuSVkjRQxky2eesjkdrp+rrxTwFhQ6NAbUeZgUV0zfm5XZE76kInbcukwXxAx\n"
86 | "lneyQy2git0voUWTK4mipfCU946rcK3+ArcanV7EDSXbRxfjBSRBD6K+XGUhIPHW\n"
87 | "brk0v1wzED1RFEHTdzLAecU50Xwic6IniM3B9URfSOmjlBRebg2sEVQavMHbzURg\n"
88 | "94aDC+EkNlHh3pOmQ/V89MBiF1xDHbZZ1gB0GszYKPHec9omSwQ5HbIDV3uf3/DQ\n"
89 | "his=\n"
90 | "-----END CERTIFICATE-----\n";
91 |
92 | // In case we ever need extra topics
93 | const int ex_num_topics = 0;
94 | const char* ex_topics[ex_num_topics];
95 | //const int ex_num_topics = 1;
96 | //const char* ex_topics[ex_num_topics] = {
97 | // "/devices/my-device/tbd/#"
98 | //};
99 |
--------------------------------------------------------------------------------
/src/CloudIoTCoreDevice.cpp:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 |
16 | #include "CloudIoTCoreDevice.h"
17 | #include "jwt.h"
18 |
19 | CloudIoTCoreDevice::CloudIoTCoreDevice() {}
20 |
21 | CloudIoTCoreDevice::CloudIoTCoreDevice(const char *project_id,
22 | const char *location,
23 | const char *registry_id,
24 | const char *device_id) {
25 | setProjectId(project_id);
26 | setLocation(location);
27 | setRegistryId(registry_id);
28 | setDeviceId(device_id);
29 | }
30 |
31 | CloudIoTCoreDevice::CloudIoTCoreDevice(const char *project_id,
32 | const char *location,
33 | const char *registry_id,
34 | const char *device_id,
35 | const char *private_key) {
36 | setProjectId(project_id);
37 | setLocation(location);
38 | setRegistryId(registry_id);
39 | setDeviceId(device_id);
40 | setPrivateKey(private_key);
41 | }
42 |
43 | unsigned long CloudIoTCoreDevice::getExpMillis() {
44 | return exp_millis;
45 | }
46 |
47 | int CloudIoTCoreDevice::getJwtExpSecs() {
48 | return jwt_exp_secs;
49 | }
50 |
51 | String CloudIoTCoreDevice::createJWT(long long int current_time) {
52 | exp_millis = millis() + (jwt_exp_secs * 1000);
53 | jwt = CreateJwt(project_id, current_time, priv_key, this->jwt_exp_secs);
54 | return jwt;
55 | }
56 |
57 | String CloudIoTCoreDevice::createJWT(long long int current_time, int exp_in_secs) {
58 | jwt_exp_secs = exp_in_secs;
59 | exp_millis = millis() + (jwt_exp_secs * 1000);
60 | jwt = CreateJwt(project_id, current_time, priv_key, exp_in_secs);
61 | return jwt;
62 | }
63 |
64 | String CloudIoTCoreDevice::getJWT() {
65 | return jwt;
66 | }
67 |
68 | String CloudIoTCoreDevice::getBasePath() {
69 | return String("/v1/projects/") + project_id + "/locations/" + location +
70 | "/registries/" + registry_id + "/devices/" + device_id;
71 | }
72 |
73 | String CloudIoTCoreDevice::getClientId(){
74 | return String("projects/") + project_id + "/locations/" + location +
75 | "/registries/" + registry_id + "/devices/" + device_id;
76 | }
77 |
78 | String CloudIoTCoreDevice::getConfigTopic(){
79 | return String("/devices/") + device_id + "/config";
80 | }
81 |
82 | String CloudIoTCoreDevice::getCommandsTopic(){
83 | return String("/devices/") + device_id + "/commands/#";
84 | }
85 |
86 | String CloudIoTCoreDevice::getDeviceId(){
87 | return String(device_id);
88 | }
89 |
90 | String CloudIoTCoreDevice::getEventsTopic(){
91 | return String("/devices/") + device_id + "/events";
92 | }
93 |
94 | String CloudIoTCoreDevice::getStateTopic(){
95 | return String("/devices/") + device_id + "/state";
96 | }
97 |
98 | String CloudIoTCoreDevice::getConfigPath(int version) {
99 | return this->getBasePath() + "/config?local_version=" + version;
100 | }
101 |
102 | String CloudIoTCoreDevice::getLastConfigPath() {
103 | return this->getConfigPath(0);
104 | }
105 |
106 | String CloudIoTCoreDevice::getSendTelemetryPath() {
107 | return this->getBasePath() + ":publishEvent";
108 | }
109 |
110 | String CloudIoTCoreDevice::getSetStatePath() {
111 | return this->getBasePath() + ":setState";
112 | }
113 |
114 | void CloudIoTCoreDevice::setJwtExpSecs(int exp_in_secs) {
115 | this->jwt_exp_secs = exp_in_secs;
116 | }
117 |
118 | CloudIoTCoreDevice &CloudIoTCoreDevice::setProjectId(const char *project_id) {
119 | this->project_id = project_id;
120 | return *this;
121 | }
122 |
123 | CloudIoTCoreDevice &CloudIoTCoreDevice::setLocation(const char *location) {
124 | this->location = location;
125 | return *this;
126 | }
127 |
128 | CloudIoTCoreDevice &CloudIoTCoreDevice::setRegistryId(const char *registry_id) {
129 | this->registry_id = registry_id;
130 | return *this;
131 | }
132 |
133 | CloudIoTCoreDevice &CloudIoTCoreDevice::setDeviceId(const char *device_id) {
134 | this->device_id = device_id;
135 | return *this;
136 | }
137 |
138 | CloudIoTCoreDevice &CloudIoTCoreDevice::setPrivateKey(const char *private_key) {
139 | if ( strlen(private_key) != (95) ) {
140 | Serial.println("Warning: expected private key to be 95, was: " +
141 | String(strlen(private_key)));
142 | }
143 | priv_key[8] = 0;
144 | for (int i = 7; i >= 0; i--) {
145 | priv_key[i] = 0;
146 | for (int byte_num = 0; byte_num < 4; byte_num++) {
147 | priv_key[i] = (priv_key[i] << 8) + strtoul(private_key, NULL, 16);
148 | private_key += 3;
149 | }
150 | }
151 | return *this;
152 | }
153 |
154 | CloudIoTCoreDevice &CloudIoTCoreDevice::setPrivateKey(const unsigned char *private_key) {
155 | priv_key[8] = 0;
156 | for (int i = 7; i >= 0; i--) {
157 | for (int byte_num = 0; byte_num < 4; byte_num++) {
158 | priv_key[i] = (priv_key[i] << 8) + *private_key;
159 | ++private_key;
160 | }
161 | }
162 | return *this;
163 | }
164 |
--------------------------------------------------------------------------------
/src/crypto/ecc.h:
--------------------------------------------------------------------------------
1 | // AUTOGENERATED, DO NOT EDIT. See CONTRIBUTING.md for instructions.
2 | /**
3 | * \defgroup ecc Elliptic Curve Point Arithmetic
4 | *
5 | * @{
6 | */
7 |
8 | /**
9 | * \file
10 | * Header file for the Elliptic Curve point arithmetic functions.
11 | * \author
12 | * Kasun Hewage
13 | *
14 | */
15 |
16 |
17 | #ifndef __ECC_H__
18 | #define __ECC_H__
19 |
20 | #include "nn.h"
21 |
22 | /**
23 | * The size of sliding window, must be power of 2 (change this if you
24 | * want to use other window size, for example: 2 or 4)
25 | */
26 | #ifdef CONF_W_BITS
27 | #define W_BITS CONF_W_BITS
28 | #else
29 | #define W_BITS 4
30 | #endif
31 |
32 | /**
33 | * Basic mask used to generate mask array (you need to change this if
34 | * you want to change window size)
35 | * For example: if W_BITS is 2, BASIC_MASK must be 0x03;
36 | * if W_BITS is 4, BASIC_MASK must be 0x0f
37 | * if W_BITS is 8, BASIC_MASK must be 0xff
38 | */
39 | //#define BASIC_MASK 0x0f
40 | #define BASIC_MASK ((1 << W_BITS) - 1)
41 |
42 | /**
43 | * Number of windows in one digit, NUM_MASKS = NN_DIGIT_BITS/W_BITS
44 | */
45 | #define NUM_MASKS (NN_DIGIT_BITS/W_BITS)
46 |
47 | /**
48 | * Number of points for precomputed points, NN_POINTS = 2^W_BITS - 1
49 | */
50 | #define NUM_POINTS ((1 << W_BITS) - 1)
51 |
52 | /**
53 | * The data structure define the elliptic curve.
54 | */
55 | typedef struct ecurve {
56 | /** curve's coefficients */
57 | NN_DIGIT a[NUMWORDS];
58 | NN_DIGIT b[NUMWORDS];
59 |
60 | /** whether a is -3 */
61 | char a_minus3;
62 |
63 | /** whether a is zero */
64 | char a_zero;
65 |
66 | } ecurve_t;
67 |
68 | /**
69 | * The data structure that defines a point of the elliptic curve.
70 | */
71 | typedef struct point {
72 | /** point's X coordinate. */
73 | NN_DIGIT x[NUMWORDS];
74 | /** point's X coordinate. */
75 | NN_DIGIT y[NUMWORDS];
76 | } point_t;
77 |
78 | /**
79 | * All the parameters needed for elliptic curve operation.
80 | */
81 | typedef struct curve_params {
82 | /** prime modulus */
83 | NN_DIGIT p[NUMWORDS];
84 |
85 | /** Omega, p = 2^m -omega */
86 | NN_DIGIT omega[NUMWORDS];
87 |
88 | /** curve over which ECC will be performed. */
89 | ecurve_t E;
90 |
91 | /** The base point, a point on E of order r */
92 | point_t G;
93 |
94 | /** A positive, prime integer dividing the number of points on E */
95 | NN_DIGIT r[NUMWORDS];
96 |
97 | // a positive prime integer, s.t. k = #E/r
98 | // NN_DIGIT k[NUMWORDS];
99 | } curve_params_t;
100 |
101 | /**
102 | * \brief Initialize parameters and basepoint array for
103 | * sliding window method. This function should be called first
104 | * before using other functions.
105 | */
106 | void ecc_init();
107 |
108 | /**
109 | * \brief Provide order of curve for the modules which need to know
110 | */
111 | void ecc_get_order(NN_DIGIT * order);
112 |
113 | /**
114 | * \brief Point addition, P0 = P1 + P2
115 | */
116 | void ecc_add(point_t * P0, point_t * P1, point_t * P2);
117 |
118 | /**
119 | * \brief Point addition, (P0,Z0) = (P1,Z1) + (P2,Z2)
120 | * using projective coordinates system.
121 | * P0, P1, P2 can be same pointer.
122 | */
123 | void ecc_add_proj(point_t * P0, NN_DIGIT *Z0, point_t * P1, NN_DIGIT * Z1, point_t * P2, NN_DIGIT * Z2);
124 |
125 | /**
126 | * \brief Point doubleing, (P0,Z0) = 2*(P1,Z1)
127 | * using projective coordinates system.
128 | * P0 and P1 can be same pointer
129 | */
130 | void ecc_dbl_proj(point_t * P0, NN_DIGIT *Z0, point_t * P1, NN_DIGIT * Z1);
131 |
132 | /**
133 | * \brief Scalar point multiplication P0 = n * P1
134 | * P0 and P1 can not be same pointer
135 | */
136 | void ecc_mul(point_t * P0, point_t * P1, NN_DIGIT * n);
137 |
138 | /**
139 | * \brief Precompute the points for sliding window method
140 | */
141 | void ecc_win_precompute(point_t * baseP, point_t * pointArray);
142 |
143 | /**
144 | * \brief Scalr point multiplication using slide window method
145 | * P0 = n * Point, this Point may not be the base point of curve
146 | * pointArray is constructed by call win_precompute(Point, pointArray)
147 | */
148 | void ecc_win_mul(point_t * P0, NN_DIGIT * n, point_t * pointArray);
149 |
150 | /**
151 | * \brief m repeated point doublings (Algorithm 3.23 in "Guide to ECC")
152 | */
153 | void ecc_m_dbl_projective(point_t * P0, NN_DIGIT *Z0, uint8_t m);
154 |
155 | /**
156 | * \brief Scalar point multiplication on basepoint, P0 = n * basepoint
157 | * using window method.
158 | * pointArray is array of basepoint,
159 | * pointArray[0] = basepoint, pointArray[1] = 2*basepoint ...
160 | */
161 | void ecc_win_mul_base(point_t * P0, NN_DIGIT * n);
162 |
163 | /**
164 | * \brief Get base point
165 | */
166 | point_t * ecc_get_base_p();
167 |
168 | /**
169 | * \brief Get the parameters of specific curve.
170 | */
171 | void get_curve_param(curve_params_t *para);
172 |
173 | /**
174 | * \brief Get the current curve parameters.
175 | */
176 | curve_params_t * ecc_get_param(void);
177 |
178 | /**
179 | * \brief Compute a public key from a secret
180 | */
181 | void ecc_gen_pub_key(NN_DIGIT *priv_key, point_t * pub);
182 |
183 |
184 | /**
185 | * \brief Compute a private key (secret)
186 | */
187 | void ecc_gen_private_key(NN_DIGIT *PrivateKey);
188 |
189 | #endif /* __ECC_H__ */
190 |
191 | /** @} */
192 |
--------------------------------------------------------------------------------
/examples/Esp8266-lwmqtt/esp8266_mqtt.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2018 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // This file contains static methods for API requests using Wifi / MQTT
16 |
17 | #include
18 | #include "FS.h"
19 |
20 | // You need to set certificates to All SSL cyphers and you may need to
21 | // increase memory settings in Arduino/cores/esp8266/StackThunk.cpp:
22 | // https://github.com/esp8266/Arduino/issues/6811
23 | #include "WiFiClientSecureBearSSL.h"
24 | #include
25 |
26 | #include
27 |
28 | #include
29 | #include
30 | #include "ciotc_config.h" // Wifi configuration here
31 |
32 |
33 | // !!REPLACEME!!
34 | // The MQTT callback function for commands and configuration updates
35 | // Place your message handler code here.
36 | void messageReceivedAdvanced(MQTTClient *client, char topic[], char bytes[], int length)
37 | {
38 | Serial.printf("Incoming Topic: %s", topic);
39 | if (length > 0)// On message
40 | {
41 | Serial.printf("\n\r Data: %s", bytes);
42 | }
43 | Serial.println();
44 | }
45 | ///////////////////////////////
46 |
47 | // Initialize WiFi and MQTT for this board
48 | static MQTTClient *mqttClient;
49 | static BearSSL::WiFiClientSecure netClient;
50 | static BearSSL::X509List certList;
51 | static CloudIoTCoreDevice device(project_id, location, registry_id, device_id);
52 | CloudIoTCoreMqtt *mqtt;
53 |
54 | ///////////////////////////////
55 | // Helpers specific to this board
56 | ///////////////////////////////
57 | String getDefaultSensor()
58 | {
59 | return "Wifi: " + String(WiFi.RSSI()) + "db";
60 | }
61 |
62 | String getJwt()
63 | {
64 | // Disable software watchdog as these operations can take a while.
65 | ESP.wdtDisable();
66 | time_t iat = time(nullptr);
67 | Serial.println("Refreshing JWT");
68 | String jwt = device.createJWT(iat, jwt_exp_secs);
69 | ESP.wdtEnable(0);
70 | return jwt;
71 | }
72 |
73 | static void readDerCert(const char *filename) {
74 | File ca = SPIFFS.open(filename, "r");
75 | if (ca)
76 | {
77 | size_t size = ca.size();
78 | uint8_t cert[size];
79 | ca.read(cert, size);
80 | certList.append(cert, size);
81 | ca.close();
82 |
83 | Serial.print("Success to open ca file ");
84 | }
85 | else
86 | {
87 | Serial.print("Failed to open ca file ");
88 | }
89 | Serial.println(filename);
90 | }
91 |
92 | static void setupCertAndPrivateKey()
93 | {
94 | // Set CA cert on wifi client
95 | // If using a static (pem) cert, uncomment in ciotc_config.h:
96 | certList.append(primary_ca);
97 | certList.append(backup_ca);
98 | netClient.setTrustAnchors(&certList);
99 |
100 | device.setPrivateKey(private_key);
101 | return;
102 |
103 | // If using the (preferred) method with the cert and private key in /data (SPIFFS)
104 | // To get the private key run
105 | // openssl ec -in -outform DER -out private-key.der
106 |
107 | if (!SPIFFS.begin())
108 | {
109 | Serial.println("Failed to mount file system");
110 | return;
111 | }
112 |
113 | readDerCert("/gtsltsr.crt"); // primary_ca.pem
114 | readDerCert("/GSR4.crt"); // backup_ca.pem
115 | netClient.setTrustAnchors(&certList);
116 |
117 |
118 | File f = SPIFFS.open("/private-key.der", "r");
119 | if (f) {
120 | size_t size = f.size();
121 | uint8_t data[size];
122 | f.read(data, size);
123 | f.close();
124 |
125 | BearSSL::PrivateKey pk(data, size);
126 | device.setPrivateKey(pk.getEC()->x);
127 |
128 | Serial.println("Success to open private-key.der");
129 | } else {
130 | Serial.println("Failed to open private-key.der");
131 | }
132 |
133 | SPIFFS.end();
134 | }
135 |
136 | static void setupWifi()
137 | {
138 | WiFi.mode(WIFI_STA);
139 | WiFi.begin(ssid, password);
140 | Serial.println("\n\r\n\rConnecting to WiFi");
141 | while (WiFi.status() != WL_CONNECTED)
142 | {
143 | delay(100);
144 | }
145 |
146 | configTime(0, 0, ntp_primary, ntp_secondary);
147 | Serial.println("Waiting on time sync...");
148 | while (time(nullptr) < 1510644967)
149 | {
150 | delay(10);
151 | }
152 | }
153 |
154 | ///////////////////////////////
155 | // Orchestrates various methods from preceeding code.
156 | ///////////////////////////////
157 | bool publishTelemetry(const String &data)
158 | {
159 | Serial.print("Outcoming: ");
160 | Serial.println(data);
161 | return mqtt->publishTelemetry(data);
162 | }
163 |
164 | bool publishTelemetry(const char *data, int length)
165 | {
166 | return mqtt->publishTelemetry(data, length);
167 | }
168 |
169 | // TODO: fix globals
170 | void setupCloudIoT()
171 | {
172 | // ESP8266 WiFi setup
173 | setupWifi();
174 |
175 | // ESP8266 WiFi secure initialization and device private key
176 | setupCertAndPrivateKey();
177 |
178 | mqttClient = new MQTTClient(512);
179 | mqttClient->setOptions(180, true, 1000); // keepAlive, cleanSession, timeout
180 | mqtt = new CloudIoTCoreMqtt(mqttClient, &netClient, &device);
181 | mqtt->setUseLts(true);
182 | mqtt->startMQTTAdvanced(); // Opens connection using advanced callback
183 | }
184 |
--------------------------------------------------------------------------------
/src/crypto/sha256.cpp:
--------------------------------------------------------------------------------
1 | // AUTOGENERATED, DO NOT EDIT. See CONTRIBUTING.md for instructions.
2 | /*********************************************************************
3 | * Filename: sha256.c
4 | * Author: Brad Conte (brad AT bradconte.com)
5 | * Copyright:
6 | * Disclaimer: This code is presented "as is" without any guarantees.
7 | * Details: Implementation of the SHA-256 hashing algorithm.
8 | SHA-256 is one of the three algorithms in the SHA2
9 | specification. The others, SHA-384 and SHA-512, are not
10 | offered in this implementation.
11 | Algorithm specification can be found here:
12 | * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
13 | This implementation uses little endian byte order.
14 |
15 | Ported to Arduino and objectified by Diego Zuccato
16 |
17 | *********************************************************************/
18 |
19 | /*************************** HEADER FILES ***************************/
20 | //#include
21 | //#include
22 | #include "sha256.h"
23 |
24 | /****************************** MACROS ******************************/
25 | #define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
26 | #define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
27 |
28 | #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
29 | #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
30 | #define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
31 | #define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
32 | #define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
33 | #define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
34 |
35 | /**************************** VARIABLES *****************************/
36 | static const WORD k[64] = {
37 | 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
38 | 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
39 | 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
40 | 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
41 | 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
42 | 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
43 | 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
44 | 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
45 | };
46 |
47 | /*********************** ACTUAL IMPLEMENTATION ***********************/
48 | Sha256::Sha256() {
49 | this->datalen = 0;
50 | this->bitlen = 0;
51 | this->state[0] = 0x6a09e667;
52 | this->state[1] = 0xbb67ae85;
53 | this->state[2] = 0x3c6ef372;
54 | this->state[3] = 0xa54ff53a;
55 | this->state[4] = 0x510e527f;
56 | this->state[5] = 0x9b05688c;
57 | this->state[6] = 0x1f83d9ab;
58 | this->state[7] = 0x5be0cd19;
59 | }
60 |
61 | void Sha256::update(const BYTE data[], size_t len) {
62 | WORD i;
63 |
64 | for (i = 0; i < len; ++i) {
65 | this->data[this->datalen] = data[i];
66 | this->datalen++;
67 | if (this->datalen == 64) {
68 | this->transform();
69 | this->bitlen += 512;
70 | this->datalen = 0;
71 | }
72 | }
73 | }
74 |
75 | void Sha256::final(BYTE hash[]) {
76 | WORD i;
77 |
78 | i = this->datalen;
79 |
80 | // Pad whatever data is left in the buffer.
81 | if (this->datalen < 56) {
82 | this->data[i++] = 0x80;
83 | while (i < 56) //@@@ optimize with memset
84 | this->data[i++] = 0x00;
85 | } else {
86 | this->data[i++] = 0x80;
87 | while (i < 64) //@@@ optimize with memset
88 | this->data[i++] = 0x00;
89 | this->transform();
90 | memset(this->data, 0, 56);
91 | }
92 |
93 | // Append to the padding the total message's length in bits and transform.
94 | this->bitlen += this->datalen * 8;
95 | this->data[63] = this->bitlen;
96 | this->data[62] = this->bitlen >> 8;
97 | this->data[61] = this->bitlen >> 16;
98 | this->data[60] = this->bitlen >> 24;
99 | this->data[59] = this->bitlen >> 32;
100 | this->data[58] = this->bitlen >> 40;
101 | this->data[57] = this->bitlen >> 48;
102 | this->data[56] = this->bitlen >> 56;
103 | this->transform();
104 |
105 | // Since this implementation uses little endian byte ordering and SHA uses big endian,
106 | // reverse all the bytes when copying the final state to the output hash.
107 | for (i = 0; i < 4; ++i) {
108 | hash[i] = (this->state[0] >> (24 - i * 8)) & 0x000000ff;
109 | hash[i + 4] = (this->state[1] >> (24 - i * 8)) & 0x000000ff;
110 | hash[i + 8] = (this->state[2] >> (24 - i * 8)) & 0x000000ff;
111 | hash[i + 12] = (this->state[3] >> (24 - i * 8)) & 0x000000ff;
112 | hash[i + 16] = (this->state[4] >> (24 - i * 8)) & 0x000000ff;
113 | hash[i + 20] = (this->state[5] >> (24 - i * 8)) & 0x000000ff;
114 | hash[i + 24] = (this->state[6] >> (24 - i * 8)) & 0x000000ff;
115 | hash[i + 28] = (this->state[7] >> (24 - i * 8)) & 0x000000ff;
116 | }
117 | }
118 |
119 | void Sha256::transform() {
120 | WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
121 |
122 | for (i = 0, j = 0; i < 16; ++i, j += 4)
123 | m[i] = (this->data[j] << 24) | (this->data[j + 1] << 16) | (this->data[j + 2] << 8) | (this->data[j + 3]);
124 | for ( ; i < 64; ++i)
125 | m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
126 |
127 | a = this->state[0];
128 | b = this->state[1];
129 | c = this->state[2];
130 | d = this->state[3];
131 | e = this->state[4];
132 | f = this->state[5];
133 | g = this->state[6];
134 | h = this->state[7];
135 |
136 | for (i = 0; i < 64; ++i) {
137 | t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
138 | t2 = EP0(a) + MAJ(a,b,c);
139 | h = g;
140 | g = f;
141 | f = e;
142 | e = d + t1;
143 | d = c;
144 | c = b;
145 | b = a;
146 | a = t1 + t2;
147 | }
148 |
149 | this->state[0] += a;
150 | this->state[1] += b;
151 | this->state[2] += c;
152 | this->state[3] += d;
153 | this->state[4] += e;
154 | this->state[5] += f;
155 | this->state[6] += g;
156 | this->state[7] += h;
157 | }
158 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/ios-gateway.ino:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2020 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 |
16 | #if defined(ARDUINO_SAMD_MKR1000) or defined(ESP8266)
17 | #define __SKIP_ESP32__
18 | #endif
19 |
20 | #if defined(ESP32)
21 | #define __ESP32_MQTT_H__
22 | #endif
23 |
24 | #if defined(ESP32)
25 | #define __ESP32_MQTT_H__
26 | #endif
27 |
28 | #ifdef __SKIP_ESP32__
29 |
30 | #include
31 |
32 | void setup(){
33 | Serial.begin(115200);
34 | }
35 |
36 | void loop(){
37 | Serial.println("Hello World");
38 | }
39 |
40 | #endif
41 |
42 | #ifdef __ESP32_MQTT_H__
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 | #include
49 |
50 | #include
51 | #include
52 |
53 | #define DHTPIN 4 // Digital pin connected to the DHT sensor
54 |
55 | #define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
56 |
57 | DHT dht(DHTPIN, DHTTYPE);
58 |
59 | BLEServer *pServer = NULL;
60 | BLECharacteristic * pNotifyCharacteristic;
61 | BLECharacteristic * pReadCharacteristic;
62 |
63 | bool deviceConnected = false;
64 | bool oldDeviceConnected = false;
65 |
66 | #define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
67 | #define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in seconds) */
68 |
69 | #define SERVICE_UUID "fdc59e94-27d1-4576-94c6-404b459c11ff" // UART service UUID
70 | #define CHARACTERISTIC_UUID_READ "fdc59e94-27d2-4576-94c6-404b459c11ff"
71 | #define CHARACTERISTIC_UUID_NOTIFY "fdc59e94-27d3-4576-94c6-404b459c11ff"
72 |
73 | #define dataTemplate "{\n\"Temperature\":%f,\n\"Humidity\":%f\n}"
74 |
75 | bool dataDump = false;
76 | uint16_t dataSize = 0;
77 |
78 | int pIndex = 0;
79 | int address = 0;
80 |
81 | #ifdef __cplusplus
82 | extern "C"
83 | {
84 | #endif
85 | uint8_t temprature_sens_read();
86 | #ifdef __cplusplus
87 | }
88 | #endif
89 | uint8_t temprature_sens_read();
90 |
91 | class MainServerCallbacks : public BLEServerCallbacks
92 | {
93 | void onConnect(BLEServer *pServer)
94 | {
95 | deviceConnected = true;
96 | };
97 |
98 | void onDisconnect(BLEServer *pServer)
99 | {
100 | deviceConnected = false;
101 | }
102 | };
103 |
104 | class ReadCallback : public BLECharacteristicCallbacks
105 | {
106 | void onRead(BLECharacteristic *pCharacteristic)
107 | {
108 | Serial.println("Got read ");
109 | }
110 | };
111 |
112 | class NotifyCallback : public BLECharacteristicCallbacks
113 | {
114 | void onWrite(BLECharacteristic *pCharacteristic)
115 | {
116 | std::string rxValue = pCharacteristic->getValue();
117 |
118 | std::string dumpStr("d");
119 |
120 | if (rxValue.length() > 0)
121 | {
122 | Serial.print("Received Value: ");
123 | Serial.println(rxValue.c_str());
124 |
125 | if (rxValue.compare(dumpStr) == 0)
126 | {
127 | dataDump = true;
128 | }
129 | }
130 | }
131 | };
132 |
133 | void setup() {
134 | Serial.begin(115200);
135 | Serial.println("Starting up");
136 | dht.begin();
137 |
138 | Wire.begin(); //creates a Wire object
139 |
140 | // Create the BLE Device
141 | BLEDevice::init("BLEDU");
142 |
143 | dataSize = 26; // Full size of external eeprom
144 |
145 | // Create the BLE Server
146 | pServer = BLEDevice::createServer();
147 | pServer->setCallbacks(new MainServerCallbacks());
148 |
149 | // Create the BLE Service
150 | BLEService *pService = pServer->createService(SERVICE_UUID);
151 |
152 | // Create a BLE Characteristic
153 | pReadCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_READ, BLECharacteristic::PROPERTY_READ);
154 | pReadCharacteristic->setCallbacks(new ReadCallback());
155 | pReadCharacteristic->setValue(dataSize); // This should changed when new data is saved.
156 |
157 | pNotifyCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_NOTIFY, BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY);
158 | pNotifyCharacteristic->setCallbacks(new NotifyCallback());
159 |
160 | // Start the service
161 | pService->start();
162 |
163 | // Start advertising the service too.
164 | pServer->getAdvertising()->addServiceUUID(SERVICE_UUID);
165 | pServer->getAdvertising()->start();
166 |
167 | Serial.println("Waiting a client connection to notify...");
168 | }
169 |
170 |
171 | void sendTemp(){
172 | char *sensorData = NULL;
173 |
174 | // Reading temperature or humidity takes about 250 milliseconds!
175 | // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
176 | float h = dht.readHumidity();
177 | // Read temperature as Celsius (the default)
178 | float t = dht.readTemperature();
179 |
180 | asprintf(&sensorData, dataTemplate, t, h);
181 |
182 | Serial.println(sensorData);
183 | if (deviceConnected)
184 | {
185 | pNotifyCharacteristic->setValue(sensorData);
186 | pNotifyCharacteristic->notify();
187 | }
188 | delay(5000);
189 | }
190 |
191 | void loop() {
192 | if (deviceConnected)
193 | {
194 | sendTemp();
195 | Serial.println("Temp Sent");
196 | }
197 | // disconnecting
198 | if (!deviceConnected && oldDeviceConnected) {
199 | delay(500); // give the bluetooth stack the chance to get things ready
200 | pServer->startAdvertising(); // restart advertising
201 | Serial.println("Start advertising");
202 | oldDeviceConnected = deviceConnected;
203 | }
204 |
205 | // connecting
206 | if (deviceConnected && !oldDeviceConnected) {
207 | oldDeviceConnected = deviceConnected;
208 | }
209 | }
210 | #endif
211 |
--------------------------------------------------------------------------------
/examples/complex/esp32/Gateway/Esp32-gateway/esp32-mqtt.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2020 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // This file contains static methods for API requests using Wifi / MQTT
16 |
17 | #include
18 | #include
19 | #include
20 |
21 | #include
22 |
23 | #include
24 | #include
25 | #include "ciotc_config.h" // Update this file with your configuration
26 | #include "connect-serial.h"
27 |
28 | // Initialize WiFi and MQTT for this board
29 | Client *netClient;
30 | CloudIoTCoreDevice *device;
31 | CloudIoTCoreMqtt *mqtt;
32 | MQTTClient *mqttClient;
33 | unsigned long iss = 0;
34 | String jwt, incomingPayload, incomingCommand, input="NOT FOUND";
35 |
36 | ///////////////////////////////
37 | // Helpers specific to this board
38 | ///////////////////////////////
39 |
40 | void getDeviceID(String payload) {
41 | char buf[payload.length() + 1];
42 | payload.toCharArray(buf, payload.length() + 1);
43 | char *pars = strtok(buf, ",");
44 | staticBTDeviceID = pars;
45 | pars = strtok(NULL, ",");
46 | incomingCommand = pars;
47 | }
48 |
49 |
50 | String getJwt() {
51 | iss = time(nullptr);
52 | Serial.println("Refreshing JWT");
53 | jwt = device->createJWT(iss, jwt_exp_secs);
54 | Serial.println(jwt);
55 | return jwt;
56 | }
57 |
58 |
59 | void setupWifi() {
60 | Serial.println("Starting wifi");
61 | WiFi.mode(WIFI_STA);
62 | WiFi.disconnect();
63 | WiFi.begin(ssid,password);
64 | Serial.println("Connecting");
65 |
66 | while (WiFi.status() != WL_CONNECTED) {
67 | Serial.println(".");
68 | delay(500);
69 | }
70 |
71 | configTime(0, 0, ntp_primary, ntp_secondary);
72 | Serial.println("Waiting on time sync...");
73 | while (time(nullptr) < 1510644967) {
74 | delay(10);
75 | }
76 | }
77 |
78 |
79 | void connectWifi() {
80 | Serial.print("checking wifi...");
81 | while (WiFi.status() != WL_CONNECTED) {
82 | Serial.print(".");
83 | delay(1000);
84 | }
85 | }
86 |
87 |
88 | void detachDelegate(String delegateId) {
89 | //subscribe to delegate configuration
90 | mqttClient->unsubscribe("/devices/"+ delegateId +"/config");
91 |
92 | //subscribe to delegate commands
93 | mqttClient->unsubscribe("/devices/"+ delegateId +"/commands/#");
94 |
95 | //attach to delegate device
96 | String dat = "{}";
97 | mqttClient->publish(
98 | String("/devices/"+ delegateId +"/detach").c_str(),
99 | dat.c_str(), false, 1);
100 | }
101 |
102 |
103 | void attachAndSubscribe(String delegateId) {
104 | //attach to delegate device
105 | String dat = "{}";
106 | mqttClient->publish(String("/devices/"+ delegateId +"/attach").c_str(),
107 | dat.c_str(), false, 1);
108 |
109 | //subscribe to delegate configuration
110 | mqttClient->subscribe("/devices/"+ delegateId +"/config", 1);
111 |
112 | //subscribe to delegate commands
113 | mqttClient->subscribe("/devices/"+ delegateId +"/commands/#", 0);
114 | }
115 |
116 |
117 | // The MQTT callback function for commands and configuration updates
118 | // This is were incoming command from the gateway gets saved,
119 | // to forward to the delegate device
120 | void messageReceived(String &topic, String &payload) {
121 | int size = sizeof(delegate_device_id) / sizeof(delegate_device_id[0]);
122 | Serial.println("incoming: " + topic + " - " + payload);
123 | getDeviceID(payload);
124 | incomingPayload = payload;
125 |
126 | if(payload == "detach") {
127 | for(int i = 0; i < size;i++) {
128 | detachDelegate(delegate_device_id[i]);
129 | mqttClient->loop();
130 | }
131 | }
132 | }
133 | ///////////////////////////////
134 |
135 | ///////////////////////////////
136 | // Orchestrates various methods from preceeding code.
137 | ///////////////////////////////
138 |
139 |
140 | bool publishTelemetry(String data) {
141 | return mqtt->publishTelemetry(data);
142 | }
143 |
144 |
145 | bool publishTelemetry(const char* data, int length) {
146 | return mqtt->publishTelemetry(data, length);
147 | }
148 |
149 |
150 | bool publishTelemetry(String subfolder, String data) {
151 | return mqtt->publishTelemetry(subfolder, data);
152 | }
153 |
154 |
155 | bool publishTelemetry(String subfolder, const char* data, int length) {
156 | return mqtt->publishTelemetry(subfolder, data, length);
157 | }
158 |
159 |
160 | bool publishDelegateTelemetry(String delegateId,String data) {
161 | return mqttClient->publish(
162 | String("/devices/"+ delegateId +"/events").c_str(),
163 | String(data).c_str(), false, 1);
164 | }
165 |
166 |
167 | bool publishDelegateState(String delegateId,String data) {
168 | return mqttClient->publish(
169 | String("/devices/"+ delegateId +"/state").c_str(),
170 | String(data).c_str(), false, 1);
171 | }
172 |
173 |
174 | // Polls sensor data from the delegate devices and forwards Cloud-to-device messages.
175 | // Message from the delegate device is semicolon terminated and takes the format:
176 | // ,,;
177 | String pollDelegate() {
178 | if (incomingPayload != "") {
179 | setupSerialBT();
180 | forwardComand(incomingPayload);
181 | incomingPayload = "";
182 |
183 | if (Serial.available()) {
184 | SerialBT.write(Serial.read());
185 | }
186 |
187 | while (!SerialBT.available()) {
188 | Serial.println(".");
189 | delay(500);
190 | }
191 |
192 | input = (SerialBT.readStringUntil(';'));
193 |
194 | if(incomingCommand == "event") {
195 | publishDelegateTelemetry(staticBTDeviceID,input);
196 | } else if(incomingCommand == "state") {
197 | publishDelegateState(staticBTDeviceID,input);
198 | }
199 |
200 | Serial.println("Delegate Published");
201 |
202 | disconnectSerialBT();
203 | } else {
204 | Serial.println("Connect - No Incoming Commands ");
205 | }
206 | return input;
207 | }
208 |
209 |
210 | void connect() {
211 | connectWifi();
212 | mqtt->mqttConnect();
213 |
214 | int size = sizeof(delegate_device_id) / sizeof(delegate_device_id[0]);
215 |
216 | for(int i = 0; i < size; i++) {
217 | attachAndSubscribe(delegate_device_id[i]);
218 | mqttClient->loop();
219 | }
220 |
221 | delay(500); // <- fixes some issues with WiFi stability
222 | }
223 |
224 |
225 | void setupCloudIoT() {
226 | device = new CloudIoTCoreDevice(
227 | project_id, location, registry_id, device_id,
228 | private_key_str);
229 |
230 | setupWifi();
231 | netClient = new WiFiClientSecure();
232 | mqttClient = new MQTTClient(360);
233 | mqttClient->setOptions(180, true, 10000); // keepAlive, cleanSession, timeout
234 | mqtt = new CloudIoTCoreMqtt(mqttClient, netClient, device);
235 | mqtt->setUseLts(true);
236 | mqtt->startMQTT();
237 | mqttClient->subscribe("/devices/"+ String(device_id) +"/errors",0);
238 | }
239 |
--------------------------------------------------------------------------------
/examples/universal-lwmqtt/universal-mqtt.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2019 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *****************************************************************************/
15 | // Detect the architecture
16 | #if defined(ESP8266)
17 | #define __ESP8266_MQTT_H__
18 | #endif
19 |
20 | #if ESP32
21 | #define __ESP32_MQTT_H__
22 | #endif
23 |
24 | #if defined(ARDUINO_SAMD_MKR1000)
25 | #define __MKR1000_MQTT_H__
26 | #endif
27 |
28 | // This file contains static methods for API requests using Wifi / MQTT
29 | #ifdef __MKR1000_MQTT_H__
30 | #include
31 | #include
32 |
33 | #include
34 |
35 | #include
36 | #include
37 | #include "ciotc_config.h" // Update this file with your configuration
38 |
39 | ///////////////////////////////
40 | // Cloud IoT configuration that you don't need to change
41 | Client *netClient;
42 | CloudIoTCoreDevice *device;
43 | CloudIoTCoreMqtt *mqtt;
44 | MQTTClient *mqttClient;
45 | unsigned long iat = 0;
46 | String jwt;
47 |
48 | ///////////////////////////////
49 | // Helpers specific to this board
50 | ///////////////////////////////
51 | String getDefaultSensor() {
52 | return "Wifi: " + String(WiFi.RSSI()) + "db";
53 | }
54 |
55 | String getJwt() {
56 | // Disable software watchdog as these operations can take a while.
57 | Serial.println("Refreshing JWT");
58 | iat = WiFi.getTime();
59 | jwt = device->createJWT(iat, jwt_exp_secs);
60 | return jwt;
61 | }
62 |
63 | void setupWifi() {
64 | Serial.println("Starting wifi");
65 |
66 | WiFi.begin(ssid, password);
67 | Serial.println("Connecting to WiFi");
68 | while (WiFi.status() != WL_CONNECTED) {
69 | delay(100);
70 | }
71 |
72 | Serial.println("Waiting on time sync...");
73 | while (WiFi.getTime() < 1510644967) {
74 | delay(10);
75 | }
76 | }
77 |
78 | void connectWifi() {
79 | Serial.print("checking wifi...");
80 | while (WiFi.status() != WL_CONNECTED) {
81 | Serial.print(".");
82 | delay(1000);
83 | }
84 | }
85 |
86 | ///////////////////////////////
87 | // Orchestrates various methods from preceeding code.
88 | ///////////////////////////////
89 | void connect() {
90 | connectWifi();
91 | mqtt->mqttConnect();
92 | }
93 |
94 | bool publishTelemetry(String data) {
95 | return mqtt->publishTelemetry(data);
96 | }
97 |
98 | bool publishTelemetry(String subfolder, String data) {
99 | return mqtt->publishTelemetry(subfolder, data);
100 | }
101 |
102 | void setupCloudIoT() {
103 | device = new CloudIoTCoreDevice(
104 | project_id, location, registry_id, device_id,
105 | private_key_str);
106 |
107 | setupWifi();
108 | netClient = new WiFiSSLClient();
109 |
110 | mqttClient = new MQTTClient(512);
111 | mqttClient->setOptions(180, true, 1000); // keepAlive, cleanSession, timeout
112 | mqtt = new CloudIoTCoreMqtt(mqttClient, netClient, device);
113 | mqtt->startMQTT();
114 | }
115 | #endif //__MKR1000_MQTT_H__
116 |
117 |
118 | #ifdef __ESP32_MQTT_H__
119 | #include
120 | #include
121 | #include
122 |
123 | #include
124 |
125 | #include
126 | #include
127 | #include "ciotc_config.h" // Update this file with your configuration
128 |
129 | // Initialize WiFi and MQTT for this board
130 | Client *netClient;
131 | CloudIoTCoreDevice *device;
132 | CloudIoTCoreMqtt *mqtt;
133 | MQTTClient *mqttClient;
134 | unsigned long iat = 0;
135 | String jwt;
136 |
137 | ///////////////////////////////
138 | // Helpers specific to this board
139 | ///////////////////////////////
140 | String getDefaultSensor() {
141 | return "Wifi: " + String(WiFi.RSSI()) + "db";
142 | }
143 |
144 | String getJwt() {
145 | iat = time(nullptr);
146 | Serial.println("Refreshing JWT");
147 | jwt = device->createJWT(iat, jwt_exp_secs);
148 | return jwt;
149 | }
150 |
151 | void setupWifi() {
152 | Serial.println("Starting wifi");
153 |
154 | WiFi.mode(WIFI_STA);
155 | // WiFi.setSleep(false); // May help with disconnect? Seems to have been removed from WiFi
156 | WiFi.begin(ssid, password);
157 | Serial.println("Connecting to WiFi");
158 | while (WiFi.status() != WL_CONNECTED) {
159 | delay(100);
160 | }
161 |
162 | configTime(0, 0, ntp_primary, ntp_secondary);
163 | Serial.println("Waiting on time sync...");
164 | while (time(nullptr) < 1510644967) {
165 | delay(10);
166 | }
167 | }
168 |
169 | void connectWifi() {
170 | Serial.print("checking wifi...");
171 | while (WiFi.status() != WL_CONNECTED) {
172 | Serial.print(".");
173 | delay(1000);
174 | }
175 | }
176 |
177 | ///////////////////////////////
178 | // Orchestrates various methods from preceeding code.
179 | ///////////////////////////////
180 | bool publishTelemetry(String data) {
181 | return mqtt->publishTelemetry(data);
182 | }
183 |
184 | bool publishTelemetry(String subfolder, String data) {
185 | return mqtt->publishTelemetry(subfolder, data);
186 | }
187 |
188 | void connect() {
189 | connectWifi();
190 | mqtt->mqttConnect();
191 | }
192 |
193 | void setupCloudIoT() {
194 | device = new CloudIoTCoreDevice(
195 | project_id, location, registry_id, device_id,
196 | private_key_str);
197 |
198 | setupWifi();
199 | netClient = new WiFiClientSecure();
200 | mqttClient = new MQTTClient(512);
201 | mqttClient->setOptions(180, true, 1000); // keepAlive, cleanSession, timeout
202 | mqtt = new CloudIoTCoreMqtt(mqttClient, netClient, device);
203 | mqtt->startMQTT();
204 | }
205 | #endif //__ESP32_MQTT_H__
206 |
207 |
208 | #ifdef __ESP8266_MQTT_H__
209 | #include
210 | #include "FS.h"
211 | #include
212 | #include
213 |
214 | #include
215 |
216 | #include
217 | #include
218 | #include "ciotc_config.h" // Wifi configuration here
219 |
220 | ///////////////////////////////
221 |
222 | // Initialize WiFi and MQTT for this board
223 | MQTTClient *mqttClient;
224 | BearSSL::WiFiClientSecure *netClient;
225 | BearSSL::X509List certList;
226 | CloudIoTCoreDevice *device;
227 | CloudIoTCoreMqtt *mqtt;
228 | unsigned long iat = 0;
229 | String jwt;
230 |
231 | ///////////////////////////////
232 | // Helpers specific to this board
233 | ///////////////////////////////
234 | String getDefaultSensor() {
235 | return "Wifi: " + String(WiFi.RSSI()) + "db";
236 | }
237 |
238 | String getJwt() {
239 | // Disable software watchdog as these operations can take a while.
240 | ESP.wdtDisable();
241 | iat = time(nullptr);
242 | Serial.println("Refreshing JWT");
243 | jwt = device->createJWT(iat, jwt_exp_secs);
244 | ESP.wdtEnable(0);
245 | return jwt;
246 | }
247 |
248 | void setupCert() {
249 | // Set CA cert on wifi client
250 | // If using a static (pem) cert, uncomment in ciotc_config.h:
251 | certList.append(primary_ca);
252 | certList.append(backup_ca);
253 | netClient->setTrustAnchors(&certList);
254 | return;
255 | }
256 |
257 | void setupWifi() {
258 | WiFi.mode(WIFI_STA);
259 | WiFi.begin(ssid, password);
260 | Serial.println("Connecting to WiFi");
261 | while (WiFi.status() != WL_CONNECTED) {
262 | delay(100);
263 | }
264 |
265 | configTime(0, 0, ntp_primary, ntp_secondary);
266 | Serial.println("Waiting on time sync...");
267 | while (time(nullptr) < 1510644967) {
268 | delay(10);
269 | }
270 | }
271 |
272 | void connectWifi() {
273 | Serial.print("checking wifi..."); // TODO: Necessary?
274 | while (WiFi.status() != WL_CONNECTED) {
275 | Serial.print(".");
276 | delay(1000);
277 | }
278 | }
279 |
280 | ///////////////////////////////
281 | // Orchestrates various methods from preceeding code.
282 | ///////////////////////////////
283 | bool publishTelemetry(String data) {
284 | return mqtt->publishTelemetry(data);
285 | }
286 |
287 | bool publishTelemetry(const char* data, int length) {
288 | return mqtt->publishTelemetry(data, length);
289 | }
290 |
291 | bool publishTelemetry(String subfolder, String data) {
292 | return mqtt->publishTelemetry(subfolder, data);
293 | }
294 |
295 | bool publishTelemetry(String subfolder, const char* data, int length) {
296 | return mqtt->publishTelemetry(subfolder, data, length);
297 | }
298 |
299 | void connect() {
300 | mqtt->mqttConnect();
301 | }
302 |
303 | // TODO: fix globals
304 | void setupCloudIoT() {
305 | // Create the device
306 | device = new CloudIoTCoreDevice(
307 | project_id, location, registry_id, device_id,
308 | private_key_str);
309 |
310 | // ESP8266 WiFi setup
311 | netClient = new WiFiClientSecure();
312 | setupWifi();
313 |
314 | // ESP8266 WiFi secure initialization
315 | setupCert();
316 |
317 | mqttClient = new MQTTClient(512);
318 | mqttClient->setOptions(180, true, 1000); // keepAlive, cleanSession, timeout
319 | mqtt = new CloudIoTCoreMqtt(mqttClient, netClient, device);
320 | mqtt->setUseLts(true); // Long-term service for MQTT
321 | mqtt->startMQTT(); // Opens connection
322 | }
323 | #endif //__ESP8266_MQTT_H__
324 |
--------------------------------------------------------------------------------
/src/crypto/ecdsa.cpp:
--------------------------------------------------------------------------------
1 | // AUTOGENERATED, DO NOT EDIT. See CONTRIBUTING.md for instructions.
2 | /**
3 | * \addtogroup ecdsa
4 | *
5 | * @{
6 | */
7 |
8 | /**
9 | * \file
10 | * Source file for the Elliptic Curve Digital Signature Algorithm functions.
11 | * \author
12 | * Kasun Hewage
13 | *
14 | */
15 | #include "ecdsa.h"
16 | #include "prng.h"
17 | #include
18 |
19 | #define TRUE 1
20 | #define FALSE 0
21 |
22 | //enable shamir trick
23 | //#define SHAMIR_TRICK
24 |
25 | #ifdef SHAMIR_TRICK
26 | /* The size of sliding window, S_W_BITS <= 8 */
27 | #define S_W_BITS 2
28 |
29 | /*
30 | * basic mask used to generate mask array
31 | * For example: if S_W_BITS is 2, BASIC_MASK must be 0x03;
32 | * if S_W_BITS is 4, BASIC_MASK must be 0x0f;
33 | * if S_W_BITS is 8, BASIC_MASK must be 0xff;
34 | */
35 | #define S_BASIC_MASK ((1 << S_W_BITS) - 1)
36 |
37 | /* number of windows in one digit, NUM_MASKS = NN_DIGIT_BITS/W_BITS */
38 | #define S_NUM_MASKS (NN_DIGIT_BITS/S_W_BITS)
39 |
40 | /* number of points for precomputed points, NN_POINTS = 2^W_BITS - 1 */
41 | #define S_NUM_POINTS ((1 << (2*S_W_BITS)) - 1)
42 |
43 | #define S_MAX ((1 << S_W_BITS) - 1)
44 |
45 | #endif /* SHAMIR_TRICK */
46 |
47 |
48 |
49 | #ifdef SHAMIR_TRICK
50 | static point_t pqBaseArray[S_NUM_POINTS];
51 | static NN_DIGIT s_mask[S_NUM_MASKS];
52 | static curve_params_t* param;
53 | #else /* defined(SLIDING_WIN) */
54 | /* precomputed array of public key(used in verification) for
55 | * sliding window method.
56 | */
57 | static point_t qBaseArray[NUM_POINTS];
58 | #endif /* SHAMIR_TRICK */
59 |
60 | static NN_DIGIT order[NUMWORDS];
61 |
62 |
63 | /*---------------------------------------------------------------------------*/
64 | #ifdef SHAMIR_TRICK
65 | static point_t * baseP;
66 | /**
67 | * \brief Shamir trick init.
68 | */
69 | static void
70 | shamir_init(point_t * pKey, point_t * pointArray)
71 | {
72 | uint16_t i;
73 | uint16_t j;
74 |
75 | baseP = ecc_get_base_p();
76 |
77 | /* max = 2^w-1
78 | * [0] = Q
79 | * [1] = 2Q
80 | * ...
81 | * [max-1] = max*Q
82 | */
83 | NN_Assign(pointArray[0].x, pKey->x, NUMWORDS);
84 | NN_Assign(pointArray[0].y, pKey->y, NUMWORDS);
85 |
86 | for(i=1; ix, NUMWORDS);
105 | NN_Assign(pointArray[S_MAX].y, baseP->y, NUMWORDS);
106 | } else if(j==0) {
107 | ecc_add(&(pointArray[S_MAX+(S_MAX+1)*i]),
108 | &(pointArray[S_MAX+(S_MAX+1)*(i-1)]),
109 | baseP);
110 | }else{
111 | ecc_add(&(pointArray[S_MAX+(S_MAX+1)*i+j]),
112 | &(pointArray[S_MAX+(S_MAX+1)*i]),
113 | &(pointArray[j-1]));
114 | }
115 | }
116 | }
117 |
118 | for(i = 0; i < S_NUM_MASKS; i++) {
119 | s_mask[i] = S_BASIC_MASK << (S_W_BITS*i);
120 | }
121 | }
122 | /*---------------------------------------------------------------------------*/
123 | /**
124 | * \brief Shamir trick
125 | *
126 | */
127 | static void
128 | shamir(point_t * P0, NN_DIGIT * u1, NN_DIGIT * u2)
129 | {
130 | int16_t i, tmp, tmp2;
131 | int8_t j, k;
132 | NN_DIGIT windex;
133 | NN_DIGIT Z0[NUMWORDS];
134 | NN_DIGIT Z1[NUMWORDS];
135 |
136 | /* clear point */
137 | NN_AssignZero(P0->x, NUMWORDS);
138 | NN_AssignZero(P0->y, NUMWORDS);
139 |
140 | /* convert to Jprojective coordinate */
141 | NN_AssignZero(Z0, NUMWORDS);
142 | NN_AssignZero(Z1, NUMWORDS);
143 | Z1[0] = 0x01;
144 |
145 | tmp = NN_Digits(u1, NUMWORDS);
146 | tmp2 = NN_Digits(u2, NUMWORDS);
147 | if(tmp2 > tmp) {
148 | tmp = tmp2;
149 | }
150 |
151 | for(i = tmp - 1; i >= 0; i--) {
152 | for(j = NN_DIGIT_BITS/S_W_BITS - 1; j >= 0; j--) {
153 | for(k = 0; k < S_W_BITS; k++) {
154 | ecc_dbl_proj(P0, Z0, P0, Z0);
155 | }
156 |
157 | if(j != 0) {
158 | windex = ((s_mask[j] & u1[i]) >> ((j-1)*S_W_BITS)) |
159 | ((s_mask[j] & u2[i]) >> (j*S_W_BITS));
160 | } else {
161 | windex = ((s_mask[j] & u1[i]) << S_W_BITS) |
162 | (s_mask[j] & u2[i]);
163 | }
164 | if(windex) {
165 | ecc_add_proj(P0, Z0, P0, Z0, &(pqBaseArray[windex-1]), Z1);
166 | }
167 | }
168 |
169 | }
170 |
171 |
172 | /* convert back to affine coordinate */
173 | if(NN_One(Z0, NUMWORDS) == FALSE) {
174 | NN_ModInv(Z1, Z0, param->p, NUMWORDS);
175 | NN_ModMultOpt(Z0, Z1, Z1, param->p, param->omega, NUMWORDS);
176 | NN_ModMultOpt(P0->x, P0->x, Z0, param->p, param->omega, NUMWORDS);
177 | NN_ModMultOpt(Z0, Z0, Z1, param->p, param->omega, NUMWORDS);
178 | NN_ModMultOpt(P0->y, P0->y, Z0, param->p, param->omega, NUMWORDS);
179 | }
180 |
181 | }
182 | #endif /* SHAMIR_TRICK */
183 | /*---------------------------------------------------------------------------*/
184 | void
185 | ecdsa_init(point_t * pb_key)
186 | {
187 | #ifdef SHAMIR_TRICK
188 | param = ecc_get_param();
189 | shamir_init(pb_key, pqBaseArray);
190 | #else /* defined(SLIDING_WIN) */
191 | /* precompute the array of public key for sliding window method */
192 | ecc_win_precompute(pb_key, qBaseArray);
193 | #endif /* SHAMIR_TRICK */
194 | /* we need to know param->r */
195 | ecc_get_order(order);
196 | }
197 |
198 | /*---------------------------------------------------------------------------*/
199 | void
200 | ecdsa_sign(uint8_t sha256sum[SHA256_DIGEST_LENGTH], NN_DIGIT *r, NN_DIGIT *s, NN_DIGIT *d)
201 | {
202 |
203 | char done = FALSE;
204 | NN_DIGIT k[NUMWORDS];
205 | NN_DIGIT k_inv[NUMWORDS];
206 | NN_DIGIT tmp[NUMWORDS];
207 | NN_DIGIT digest[NUMWORDS];
208 | point_t P;
209 | NN_DIGIT sha256tmp[SHA256_DIGEST_LENGTH/NN_DIGIT_LEN];
210 | NN_UINT result_bit_len;
211 | NN_UINT order_bit_len;
212 |
213 | while(!done) {
214 | ecc_gen_private_key(k);
215 |
216 | if((NN_Zero(k, NUMWORDS)) == 1) {
217 | continue;
218 | }
219 |
220 | ecc_win_mul_base(&P, k);
221 |
222 | NN_Mod(r, P.x, NUMWORDS, order, NUMWORDS);
223 |
224 | if((NN_Zero(r, NUMWORDS)) == 1) {
225 | continue;
226 | }
227 | NN_ModInv(k_inv, k, order, NUMWORDS);
228 |
229 | NN_Decode(sha256tmp, SHA256_DIGEST_LENGTH/NN_DIGIT_LEN, sha256sum, SHA256_DIGEST_LENGTH);
230 |
231 | result_bit_len = NN_Bits(sha256tmp, SHA256_DIGEST_LENGTH / NN_DIGIT_LEN);
232 | order_bit_len = NN_Bits(order, NUMWORDS);
233 |
234 | if (result_bit_len > order_bit_len) {
235 | NN_Mod(digest, sha256tmp, SHA256_DIGEST_LENGTH/NN_DIGIT_LEN, order, NUMWORDS);
236 |
237 | } else
238 | {
239 | memset(digest, 0, NUMBYTES);
240 | NN_Assign(digest, sha256tmp, SHA256_DIGEST_LENGTH / NN_DIGIT_LEN);
241 | if (result_bit_len == order_bit_len) {
242 | NN_ModSmall(digest, order, NUMWORDS);
243 | }
244 | }
245 |
246 | NN_ModMult(k, d, r, order, NUMWORDS);
247 | NN_ModAdd(tmp, digest, k, order, NUMWORDS);
248 | NN_ModMult(s, k_inv, tmp, order, NUMWORDS);
249 | if((NN_Zero(s, NUMWORDS)) != 1) {
250 | done = TRUE;
251 | }
252 | }
253 |
254 | }
255 | /*---------------------------------------------------------------------------*/
256 | uint8_t
257 | ecdsa_verify(uint8_t sha256sum[SHA256_DIGEST_LENGTH], NN_DIGIT *r, NN_DIGIT *s, point_t *Q)
258 | {
259 | NN_DIGIT sha256tmp[SHA256_DIGEST_LENGTH/NN_DIGIT_LEN];
260 | NN_DIGIT w[NUMWORDS];
261 | NN_DIGIT u1[NUMWORDS];
262 | NN_DIGIT u2[NUMWORDS];
263 | NN_DIGIT digest[NUMWORDS];
264 | #ifndef SHAMIR_TRICK
265 | point_t u1P, u2Q;
266 | #endif
267 | point_t final;
268 | NN_UINT result_bit_len;
269 | NN_UINT order_bit_len;
270 |
271 | /* r and s should be in [1, p-1] */
272 | if((NN_Cmp(r, order, NUMWORDS)) >= 0) {
273 | return 3;
274 | }
275 | if((NN_Zero(r, NUMWORDS)) == 1) {
276 | return 4;
277 | }
278 | if((NN_Cmp(s, order, NUMWORDS)) >= 0) {
279 | return 5;
280 | }
281 | if((NN_Zero(s, NUMWORDS)) == 1) {
282 | return 6;
283 | }
284 |
285 | /* w = s^-1 mod p */
286 | NN_ModInv(w, s, order, NUMWORDS);
287 |
288 | memset(digest, 0, NUMBYTES);
289 | NN_Decode(sha256tmp, SHA256_DIGEST_LENGTH/NN_DIGIT_LEN, sha256sum, SHA256_DIGEST_LENGTH);
290 |
291 | result_bit_len = NN_Bits(sha256tmp, SHA256_DIGEST_LENGTH / NN_DIGIT_LEN);
292 | order_bit_len = NN_Bits(order, NUMWORDS);
293 | if (result_bit_len > order_bit_len) {
294 | NN_Mod(digest, sha256tmp, SHA256_DIGEST_LENGTH/NN_DIGIT_LEN, order, NUMWORDS);
295 | } else {
296 | NN_Assign(digest, sha256tmp, SHA256_DIGEST_LENGTH / NN_DIGIT_LEN);
297 | if (result_bit_len == order_bit_len) {
298 | NN_ModSmall(digest, order, NUMWORDS);
299 | }
300 | }
301 |
302 | /* u1 = ew mod p */
303 | NN_ModMult(u1, digest, w, order, NUMWORDS);
304 | /* u2 = rw mod p */
305 | NN_ModMult(u2, r, w, order, NUMWORDS);
306 |
307 | /* u1P+u2Q */
308 | #ifdef SHAMIR_TRICK
309 | shamir(&final, u1, u2);
310 | #else
311 | ecc_win_mul_base(&u1P, u1);
312 | ecc_win_mul(&u2Q, u2, qBaseArray);
313 | ecc_add(&final, &u1P, &u2Q);
314 | #endif
315 |
316 | result_bit_len = NN_Bits(final.x, NUMWORDS);
317 | order_bit_len = NN_Bits(order, NUMWORDS);
318 |
319 | if (result_bit_len > order_bit_len) {
320 | NN_Mod(w, final.x, NUMWORDS, order, NUMWORDS);
321 | } else {
322 | NN_Assign(w, final.x, NUMWORDS);
323 | if (result_bit_len == order_bit_len) {
324 | NN_ModSmall(w, order, NUMWORDS);
325 | }
326 | }
327 |
328 | if((NN_Cmp(w, r, NUMWORDS)) == 0) {
329 | return 1;
330 | } else {
331 | return 2;
332 | }
333 | }
334 |
335 | /**
336 | * @}
337 | */
338 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Google Cloud IoT JWT
2 |
3 | This is an example of how to generate JSON Web Token (JWT) credentials for
4 | connecting to Google Cloud IoT Core.
5 |
6 | This contains two parts: a library to make a JWT (json web token) which is used
7 | to authenticate with Google Cloud IoT, and Arduino sketches that demonstrate
8 | how to connect to Google Cloud IoT using the available MQTT bridge.
9 |
10 | **This example is not an officially supported Google product, does not have a
11 | SLA/SLO, and should not be used in production.**
12 |
13 | ## Supported hardware targets
14 |
15 | Currently, we support the following hardware targets:
16 |
17 | * Genuino MKR1000 and WiFi1010
18 | * Espressif ESP32
19 | * Espressif ESP8266
20 |
21 | ## Dependencies
22 | Some examples use specific dependencies that need to be installed via the Arduino Library manager.
23 |
24 | * [lwMQTT](https://github.com/256dpi/arduino-mqtt)
25 |
26 | ## Quickstart
27 |
28 | First, install the library using the Arduino Library Manager.
29 | * Open Arduino and select the **Sketch > Include Library > Library Manager**
30 | menu item.
31 | * In the filter box, search for "Google Cloud IoT JWT".
32 | * Install the library
33 |
34 | Next, enable the Cloud IoT Core API by opening the [Google Cloud IoT Core console](https://console.cloud.google.com/iot/).
35 |
36 | Next, create your device registry as described in [the Quickstart](https://cloud.google.com/iot/docs/quickstart)
37 | or by using the [Google Cloud SDK](https://cloud.google.com/sdk).
38 |
39 | If you're using the SDK, the following commands will setup PubSub and Cloud IoT
40 | Core for testing on your Arduino device:
41 |
42 | Create the PubSub topic and subscription:
43 |
44 | gcloud pubsub topics create atest-pub --project=YOUR_PROJECT_ID
45 | gcloud pubsub subscriptions create atest-sub --topic=atest-pub
46 |
47 | Create the Cloud IoT Core registry:
48 |
49 | gcloud iot registries create atest-registry \
50 | --region=us-central1 --event-notification-config=topic=atest-pub
51 |
52 | Generate an Eliptic Curve (EC) private / public key pair:
53 |
54 | openssl ecparam -genkey -name prime256v1 -noout -out ec_private.pem
55 | openssl ec -in ec_private.pem -pubout -out ec_public.pem
56 |
57 | Register the device using the keys you generated:
58 |
59 | gcloud iot devices create atest-dev --region=us-central1 \
60 | --registry=atest-registry \
61 | --public-key path=ec_public.pem,type=es256
62 |
63 | At this point, your registry is created and your device has been added to the
64 | registry so you're ready to connect it.
65 |
66 | Select one of the available samples from the **File > Examples > Google Cloud IoT Core JWT**
67 | menu and find the configuration section (ciotc_config.h in newer examples).
68 |
69 | Find and replace the following values first:
70 | * Project ID (get from console or `gcloud config list`)
71 | * Location (default is `us-central1`)
72 | * Registry ID (created in previous steps, e.g. `atest-reg`)
73 | * Device ID (created in previous steps, e.g. `atest-device`)
74 |
75 | You will also need to extract your private key using the following command:
76 |
77 | openssl ec -in ec_private.pem -noout -text
78 |
79 | ... and will need to copy the output for the private key bytes into the private
80 | key string in your Arduino project.
81 |
82 | When you run the sample, the device will connect and receive configuration
83 | from Cloud IoT Core. When you change the configuration in the Cloud IoT Core
84 | console, that configuration will be reflrected on the device.
85 |
86 | Before the examples will work, you will also need to configure the root
87 | certificate as described in the configuration headers.
88 |
89 | After you have published telemetry data, you can read it from the PubSub topic
90 | using the [Google Cloud SDK](https://cloud.google.com/sdk). With the SDK installed,
91 | run the following command to create a :
92 |
93 | ```
94 | gcloud pubsub subscriptions create --topic=
95 | ```
96 |
97 | Then read the telemetry messages:
98 | ```
99 | gcloud pubsub subscriptions pull --limit 500 --auto-ack
100 | ```
101 |
102 | ## Notes on the certificate
103 |
104 | The [root certificate from Google](https://pki.goog/roots.pem) is used to verify communication to
105 | Google. Although unlikely, it's possible for the certificate to expire or rotate, requiring you to
106 | update it.
107 |
108 | If you're using the ESP8266 project, you need to either install the Certificate to SPIFFS
109 | using the [SPIFFS upload utility](https://github.com/esp8266/arduino-esp8266fs-plugin) or
110 | will need to uncomment the certificate bytes in the sample. Note that the SPIFFS utility simply
111 | uploads the files stored in the **data** subfolder. The sample assumes the file is called `ca.crt`:
112 |
113 | ├── Esp8266...
114 | │ ├── data
115 | │ │ └── ca.crt
116 |
117 | To convert the certificate to the DER format, the following command shuold be used:
118 |
119 | wget pki.goog/roots.pem
120 | openssl x509 -outform der -in roots.pem -out ca.crt
121 |
122 | If you're using the ESP32, you can paste the certificate bytes (don't forget the \n characters)
123 | into the sample. You can use any of the root certificate bytes for the certificates with Google
124 | Trust Services (GTS) as the certificate authority (CA). This is easy to get using curl, e.g.
125 |
126 | curl pki.goog/roots.pem
127 |
128 | If you're using Genuino boards like the MKR1000, you will need to add SSL certificates to your
129 | board as [described on Hackster.io](https://www.hackster.io/arichetta/add-ssl-certificates-to-mkr1000-93c89d).
130 | The MQTT server address is `mqtt.googleapis.com` and the port is either `8883` for most cases or `443` in
131 | case your device is running in an environment where port 8883 is blocked. For long-term support,
132 | the server is `mqtt.2030.ltsapis.goog`.
133 |
134 | In future versions of this library, the MQTT domain and certificates will be changed for long term support (LTS) to:
135 |
136 | * MQTT LTS Domain - mqtt.2030.ltsapis.goog
137 | * Primary cert - [https://pki.goog/gtsltsr/gtsltsr.crt](https://pki.goog/gtsltsr/gtsltsr.crt)
138 | * Backup cert - [https://pki.goog/gsr4/GSR4.crt](https://pki.goog/gsr4/GSR4.crt)
139 |
140 | The following examples show how to regenerate the certificates:
141 |
142 | ### Create Registry keys
143 | ```
144 | openssl genpkey -algorithm RSA -out ca_private_registry.pem -pkeyopt rsa_keygen_bits:2048
145 | sudo openssl req -x509 -new -nodes -key ca_private_registry.pem -sha256 -out ca_cert_registry.pem -subj "/CN=unused"
146 | gcloud iot registries credentials create --path=ca_cert_registry.pem --project=secret --registry=secret --region=us-central1
147 | ```
148 |
149 |
150 | ### Create Elipitic device keys
151 | ```
152 | openssl ecparam -genkey -name prime256v1 -noout -out ec_private_device1.pem
153 | sudo openssl req -new -sha256 -key ec_private_device1.pem -out ec_cert_device1.csr -subj "/CN=unused-device"
154 | sudo openssl x509 -req -in ec_cert_device1.csr -CA ca_cert_registry.pem -CAkey ca_private_registry.pem -CAcreateserial -sha256 -out ec_cert_device1.pem
155 | gcloud iot devices create device1 --region=us-central1 --registry=secret --public-key path=ec_cert_device1.pem,type=es256-x509-pem
156 | ```
157 |
158 | ### Print info to copy to code
159 | ```
160 | openssl ec -in ec_private_device1.pem -noout -text
161 | echo "Copy private part of above to esp8266 code"
162 | ```
163 |
164 | ## For more information
165 |
166 | * [Access Google Cloud IoT Core from Arduino](https://medium.com/@gguuss/accessing-cloud-iot-core-from-arduino-838c2138cf2b)
167 | * [Building Google Cloud-Connected Sensors](https://medium.com/@gguuss/building-google-cloud-connected-sensors-2d46a1c58012)
168 | * [Arduino and Google Cloud IoT](https://medium.com/@gguuss/arduino-and-google-cloud-iot-e2082e0ac000)
169 | * [Experimenting with Robots and Cloud IoT Core](https://medium.com/@gguuss/experimenting-with-robots-and-cloud-iot-core-790ee17345ef)
170 | * [Arduino Hexspider Revisited](https://medium.com/@gguuss/hexspider-robot-revisited-d78ff7ce9b6c)
171 | * [TBD FAQ](https://github.com/GoogleCloudPlatform/google-cloud-iot-arduino/issues/92)
172 | * [As featured in Google Cloud I/O 2018](https://www.youtube.com/watch?v=7kpE44tXQak&t=1701s)
173 |
174 | ## Demos
175 |
176 | You can see the Arduino client library in action in [the Cloud IoT Demo from Google I/O 2018](https://www.youtube.com/watch?v=7kpE44tXQak#T=28m)
177 |
178 | ## Error codes, Debugging, and Troubleshooting
179 |
180 | The error codes for the lwMQTT library are listed [in this header file](https://github.com/256dpi/arduino-mqtt/blob/master/src/lwmqtt/lwmqtt.h#L16-L29).
181 |
182 | If you're having trouble determining what's wrong, it may be helpful to enable more verbose debugging in Arduino by setting the debug level in the IDE under **Tools > Core Debug Level > Verbose**.
183 |
184 | If you are using newer versions of the ESP8266 SDK, you need to set SSL support to "All SSL Cyphers" and you may need to modify the memory settings in BearSSL by modifying [Arduino/cores/esp8266/StackThunk.cpp](https://github.com/esp8266/Arduino/issues/6811).
185 |
186 | A few things worth checking while troubleshooting:
187 | * Is billing enabled for your project?
188 | * Is the PubSub topic configured with your device registry valid?
189 | * Is the [JWT valid](https://jwt.io)?
190 | * Are the values setup in `ciotc_config.h` appearing correctly in `*_mqtt.h`?
191 |
192 | ## Known issues
193 |
194 | Some private keys do not correctly encode to the Base64 format that required
195 | for the device bridge. If you've tried everything else, try regenerating your
196 | device credentials and registering your device again with
197 |
198 | gcloud iot devices create ...
199 |
200 | Some users have encountered issues with certain versions of the Community SDK
201 | for Espressif, if you've tried everything else, try using the SDK 2.4.2.
202 |
203 | ## License
204 |
205 | Apache 2.0; see [LICENSE](LICENSE) for details.
206 |
207 | ## Disclaimer
208 |
209 | This project is not an official Google project. It is not supported by Google
210 | and Google specifically disclaims all warranties as to its quality,
211 | merchantability, or fitness for a particular purpose.
212 |
--------------------------------------------------------------------------------
/examples/complex/esp32/camera/camera.ino:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Copyright 2019 Google
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * 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
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *
15 | *****************************************************************************/
16 |
17 | /*********
18 | This demo does the following:
19 | 1. Loads small image from OV2640 camera
20 | 2. Optionally base64-encodes payload data
21 | 3. Transmits encoded bytes to Google Cloud
22 |
23 | Portions of the code used here are based on the following tutorial:
24 | https://randomnerdtutorials.com/esp32-cam-video-streaming-web-server-camera-home-assistant/
25 |
26 | ...and bearing the following notice to be distributed code:
27 | """
28 | IMPORTANT!!!
29 | - Select Board "ESP32 Wrover Module"
30 | - Select the Partion Scheme "Huge APP (3MB No OTA)
31 | - GPIO 0 must be connected to GND to upload a sketch
32 | - After connecting GPIO 0 to GND, press the ESP32-CAM on-board RESET button to put your board in flashing mode
33 |
34 | Permission is hereby granted, free of charge, to any person obtaining a copy
35 | of this software and associated documentation files.
36 |
37 | The above copyright notice and this permission notice shall be included in all
38 | copies or substantial portions of the Software.
39 | """
40 | *********/
41 | #if defined(ESP8266) or defined(ARDUINO_SAMD_MKR1000)
42 | #define __SKIP_ESP32__
43 | #endif
44 |
45 | #if defined(ESP32)
46 | #define __ESP32_MQTT__
47 | #endif
48 |
49 | #ifdef __SKIP_ESP32__
50 |
51 | #include
52 |
53 | void setup(){
54 | Serial.begin(115200);
55 | }
56 |
57 | void loop(){
58 | Serial.println("Hello World");
59 | }
60 |
61 | #endif
62 |
63 | #ifdef __ESP32_MQTT__
64 |
65 | #include "esp_camera.h"
66 | #include
67 | #include "esp_timer.h"
68 | #include "fb_gfx.h"
69 | #include "img_converters.h"
70 | #include "soc/soc.h" //disable brownout problems
71 | #include "soc/rtc_cntl_reg.h" //disable brownout problems
72 | #include "Arduino.h"
73 | #include "SPIFFS.h"
74 | #include
75 |
76 | #include "base64.h"
77 | #include "esp32-mqtt.h"
78 |
79 |
80 | #define CAMERA_LED_GPIO 13
81 | //#define CAMERA_MODEL_M5STACK_WITHOUT_PSRAM
82 | //#define CAMERA_MODEL_M5STACK_PSRAM
83 | #define CAMEAR_MODEL_M5STACK_PSRAM_ALT
84 |
85 | #if defined(CAMERA_MODEL_M5STACK_WITHOUT_PSRAM)
86 | #define PWDN_GPIO_NUM -1
87 | #define RESET_GPIO_NUM 15
88 | #define XCLK_GPIO_NUM 27
89 | #define SIOD_GPIO_NUM 25
90 | #define SIOC_GPIO_NUM 23
91 |
92 | #define Y9_GPIO_NUM 19
93 | #define Y8_GPIO_NUM 36
94 | #define Y7_GPIO_NUM 18
95 | #define Y6_GPIO_NUM 39
96 | #define Y5_GPIO_NUM 5
97 | #define Y4_GPIO_NUM 34
98 | #define Y3_GPIO_NUM 35
99 | #define Y2_GPIO_NUM 17
100 | #define VSYNC_GPIO_NUM 22
101 | #define HREF_GPIO_NUM 26
102 | #define PCLK_GPIO_NUM 21
103 |
104 | #elif defined(CAMERA_MODEL_M5STACK_PSRAM)
105 | #define PWDN_GPIO_NUM -1
106 | #define RESET_GPIO_NUM 15
107 | #define XCLK_GPIO_NUM 27
108 | #define SIOD_GPIO_NUM 25
109 | #define SIOC_GPIO_NUM 23
110 |
111 | #define Y9_GPIO_NUM 19
112 | #define Y8_GPIO_NUM 36
113 | #define Y7_GPIO_NUM 18
114 | #define Y6_GPIO_NUM 39
115 | #define Y5_GPIO_NUM 5
116 | #define Y4_GPIO_NUM 34
117 | #define Y3_GPIO_NUM 35
118 | #define Y2_GPIO_NUM 32
119 | #define VSYNC_GPIO_NUM 22
120 | #define HREF_GPIO_NUM 26
121 | #define PCLK_GPIO_NUM 21
122 |
123 | #elif defined(CAMEAR_MODEL_M5STACK_PSRAM_ALT)
124 | #define PWDN_GPIO_NUM -1
125 | #define RESET_GPIO_NUM 15
126 | #define XCLK_GPIO_NUM 27
127 | #define SIOD_GPIO_NUM 22
128 | #define SIOC_GPIO_NUM 23
129 |
130 | #define Y9_GPIO_NUM 19
131 | #define Y8_GPIO_NUM 36
132 | #define Y7_GPIO_NUM 18
133 | #define Y6_GPIO_NUM 39
134 | #define Y5_GPIO_NUM 5
135 | #define Y4_GPIO_NUM 34
136 | #define Y3_GPIO_NUM 35
137 | #define Y2_GPIO_NUM 32
138 | #define VSYNC_GPIO_NUM 25
139 | #define HREF_GPIO_NUM 26
140 | #define PCLK_GPIO_NUM 21
141 |
142 | #else
143 | #error "Camera model not selected"
144 | #endif
145 |
146 | void setup() {
147 | WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
148 |
149 | Serial.begin(115200);
150 | Serial.setDebugOutput(false);
151 |
152 | camera_config_t config;
153 | config.ledc_channel = LEDC_CHANNEL_0;
154 | config.ledc_timer = LEDC_TIMER_0;
155 | config.pin_d0 = Y2_GPIO_NUM;
156 | config.pin_d1 = Y3_GPIO_NUM;
157 | config.pin_d2 = Y4_GPIO_NUM;
158 | config.pin_d3 = Y5_GPIO_NUM;
159 | config.pin_d4 = Y6_GPIO_NUM;
160 | config.pin_d5 = Y7_GPIO_NUM;
161 | config.pin_d6 = Y8_GPIO_NUM;
162 | config.pin_d7 = Y9_GPIO_NUM;
163 | config.pin_xclk = XCLK_GPIO_NUM;
164 | config.pin_pclk = PCLK_GPIO_NUM;
165 | config.pin_vsync = VSYNC_GPIO_NUM;
166 | config.pin_href = HREF_GPIO_NUM;
167 | config.pin_sscb_sda = SIOD_GPIO_NUM;
168 | config.pin_sscb_scl = SIOC_GPIO_NUM;
169 | config.pin_pwdn = PWDN_GPIO_NUM;
170 | config.pin_reset = RESET_GPIO_NUM;
171 | config.xclk_freq_hz = 20000000;
172 | config.pixel_format = PIXFORMAT_JPEG;
173 |
174 | if(psramFound()){
175 | config.frame_size = FRAMESIZE_SVGA;//FRAMESIZE_UXGA;
176 | config.jpeg_quality = 10;
177 | config.fb_count = 1;
178 | } else {
179 | config.frame_size = FRAMESIZE_VGA;
180 | config.jpeg_quality = 12;
181 | config.fb_count = 1;
182 | }
183 |
184 | // Camera init
185 | esp_err_t err = esp_camera_init(&config);
186 | if (err != ESP_OK) {
187 | Serial.printf("Camera init failed with error 0x%x", err);
188 | //return;
189 | }else{
190 | Serial.println("Camera settings seem to be correct!");
191 | }
192 |
193 | //pinMode(CAMERA_LED_GPIO, OUTPUT);
194 | //digitalWrite(CAMERA_LED_GPIO, HIGH);
195 |
196 | WiFi.disconnect(true);
197 |
198 |
199 | Serial.println("Starting network");
200 | //digitalWrite(CAMERA_LED_GPIO, LOW);
201 | delay(500);
202 | WiFi.mode(WIFI_STA);
203 | WiFi.begin(ssid, password);
204 | Serial.println("Connecting to WiFi");
205 | bool on = false;
206 | //digitalWrite(CAMERA_LED_GPIO, HIGH);
207 | while (WiFi.status() != WL_CONNECTED) {
208 | WiFi.waitForConnectResult();
209 | }
210 | Serial.println("\nConnected!");
211 | Serial.print("IP address: ");
212 | Serial.println(WiFi.localIP());
213 |
214 | setupCloudIoT();
215 |
216 | digitalWrite(CAMERA_LED_GPIO, LOW);
217 |
218 | if (!SPIFFS.begin(true)) {
219 | Serial.println("An Error has occurred while mounting SPIFFS");
220 | return;
221 | }
222 | }
223 |
224 |
225 | /**
226 | * This function uses SPIFFS as swap space for temporarily storing the
227 | * temporary base64-encoded image.
228 | */
229 | void publishTelemetryFromFile() {
230 | File file = SPIFFS.open("/b64image.txt", FILE_READ);
231 | if (!file) {
232 | Serial.println("There was an error opening the file for read");
233 | return;
234 | } else {
235 | Serial.println("Publishing data using temp file");
236 | }
237 | char* data = (char*)heap_caps_malloc(file.size(), MALLOC_CAP_8BIT);
238 |
239 | int i=0;
240 | while(file.available()){
241 | data[i++] = file.read();
242 | }
243 | Serial.println(String(i) + " bytes read");
244 |
245 | delay(10);
246 | mqtt->loop();
247 | mqtt->publishTelemetry(data, file.size());
248 | mqtt->loop();
249 | delay(10);
250 | file.close();
251 | Serial.println("Done publish.");
252 | }
253 |
254 |
255 | /**
256 | * Captures an image using the camera library and transmits it to Google
257 | * Cloud IoT Core.
258 | */
259 | void transmitImage() {
260 | digitalWrite(CAMERA_LED_GPIO, HIGH);
261 |
262 | // Retrieve camera framebuffer
263 | camera_fb_t * fb = NULL;
264 | uint8_t* _jpg_buf = NULL;
265 | esp_err_t res = ESP_OK;
266 | size_t frame_size = 0;
267 |
268 | fb = esp_camera_fb_get();
269 | if (!fb) {
270 | Serial.println("Camera capture failed");
271 | res = ESP_FAIL;
272 | } else {
273 | if(fb->width > 400){
274 | Serial.println(fb->format);
275 | Serial.println(fb->len);
276 | if(fb->format != PIXFORMAT_JPEG){
277 | Serial.println("Compressing");
278 | bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &frame_size);
279 | esp_camera_fb_return(fb);
280 | fb = NULL;
281 | if(!jpeg_converted){
282 | Serial.println("JPEG compression failed");
283 | res = ESP_FAIL;
284 | }
285 | } else {
286 | frame_size = fb->len;
287 | _jpg_buf = fb->buf;
288 | }
289 | }
290 | }
291 | if (res != ESP_OK) {
292 | ESP_LOGW(TAG, "Camera capture failed with error = %d", err);
293 | return;
294 | }
295 |
296 | publishTelemetry((char*)_jpg_buf, frame_size);
297 | digitalWrite(CAMERA_LED_GPIO, LOW);
298 | }
299 |
300 | // The MQTT callback function for commands and configuration updates
301 | // Place your message handler code here.
302 | void messageReceived(String &topic, String &payload) {
303 | Serial.println("incoming: " + topic + " - " + payload);
304 | // Uncomment to transmit image when receiving commands
305 | // Note: If your device is named command, this will send images on all
306 | // messages such as configuration change which is sent on connect.
307 | if (topic.lastIndexOf("/command") > 0) {
308 | Serial.println("Transmit image on receieve command");
309 | transmitImage();
310 | }
311 | }
312 | ///////////////////////////////
313 |
314 |
315 |
316 | int imageWaitMillis = 30000;
317 | unsigned long lastTransmit = millis();
318 | void loop() {
319 | /*
320 | // Transmit every 30 seconds?
321 | if (millis() > lastTransmit + imageWaitMillis) {
322 | transmitImage();
323 | lastTransmit = millis();
324 | }
325 | */
326 |
327 | // Transmit anytime there's serial input
328 | if (Serial.available() > 0) {
329 | // Clear any outstanding input, just one image per head banger
330 | while(Serial.available() > 0) {
331 | Serial.read();
332 | }
333 | transmitImage();
334 | }
335 | delay(10); // <- fixes some issues with WiFi stability
336 |
337 | if (!mqttClient->connected()) {
338 | connect();
339 | } else {
340 | mqtt->loop();
341 | }
342 | }
343 | #endif
344 |
--------------------------------------------------------------------------------
/examples/complex/esp32/ios-gateway/extras/iOS_IoTCore_Client_Demo/IoTBLEClient.swift:
--------------------------------------------------------------------------------
1 | //**************************************************************************
2 | // Copyright 2020 Google
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // 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
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | // *****************************************************************************/
15 |
16 | import UIKit
17 | import SwiftUI
18 | import SwiftJWT
19 | import CocoaMQTT
20 | import AVKit
21 | import CoreLocation
22 | import CoreBluetooth
23 | import Combine
24 |
25 | class IoTBLEView: UIViewController, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate {
26 |
27 | var centralManager: CBCentralManager?
28 | var peripheral: CBPeripheral?
29 | var dumpDataCharacteristic: CBCharacteristic?
30 |
31 | let serviceUUID = CBUUID(string: "fdc59e94-27d1-4576-94c6-404b459c11ff")
32 | let dataUUID = CBUUID(string: "fdc59e94-27d3-4576-94c6-404b459c11ff")
33 | let readUUID = CBUUID(string: "fdc59e94-27d2-4576-94c6-404b459c11ff")
34 |
35 | let delegate = contentViewDelegate()
36 |
37 | var size: UInt16 = 0;
38 | var allData: Data = Data(capacity: 1)
39 | var disconnectValue = false
40 | var didDisconnect = false
41 | var mqtt:CocoaMQTT?
42 |
43 | private var cancellable: AnyCancellable!
44 |
45 | override func viewDidLoad() {
46 | super.viewDidLoad()
47 |
48 | let centralQueue: DispatchQueue = DispatchQueue(label: "com.IoTCore.BLE", attributes: .concurrent)
49 | centralManager = CBCentralManager(delegate: self, queue: centralQueue)
50 |
51 |
52 | self.cancellable = delegate.$toDisconnect.sink{ value in
53 | print(value)
54 | if(value == true){
55 |
56 | self.mqtt!.disconnect()
57 | self.didDisconnect = true
58 | self.connected = false
59 | }
60 | else if(self.didDisconnect == true && value == false){
61 | self.didDisconnect = false
62 | self.connected = true
63 | self.getJWT()
64 | }
65 | }
66 |
67 | }
68 |
69 |
70 | func centralManagerDidUpdateState(_ central: CBCentralManager) {
71 | switch central.state {
72 | case .unknown:
73 | print("Bluetooth status is UNKNOWN")
74 | case .resetting:
75 | print("Bluetooth status is RESETTING")
76 | case .unsupported:
77 | print("Bluetooth status is UNSUPPORTED")
78 | case .unauthorized:
79 | print("Bluetooth status is UNAUTHORIZED")
80 | case .poweredOff:
81 | print("Bluetooth status is POWERED OFF")
82 | case .poweredOn:
83 | print("Bluetooth status is POWERED ON")
84 | centralManager?.scanForPeripherals(withServices: [serviceUUID])
85 | } // END switch
86 | }
87 |
88 |
89 | @IBSegueAction func swiftUIAction(_ coder: NSCoder) -> UIViewController? {
90 | getJWT()
91 | return UIHostingController(coder: coder, rootView:SwiftUIClient(delegate: delegate, viewController: self))
92 | }
93 |
94 |
95 | @Published var switchIsOn = true
96 | @Published var command = ""
97 | @Published var sensorData = ""
98 | @Published var connected = true
99 |
100 |
101 | struct MyClaims: Claims {
102 | let iat: Date
103 | let exp: Date
104 | let aud: String
105 | }
106 |
107 |
108 | func getJWT(){
109 | let myHeader = Header()
110 | let myClaims = MyClaims(iat: Date(timeIntervalSinceNow: 0),exp: Date(timeIntervalSinceNow: 3600), aud: "{project-id}")
111 |
112 | var myJWT = JWT(header: myHeader, claims: myClaims)
113 |
114 | let privateKeyPath = """
115 | -----BEGIN EC PRIVATE KEY-----
116 |
117 | -----END EC PRIVATE KEY-----
118 | """
119 |
120 | let privKey: Data = privateKeyPath.data(using: .utf8)!
121 | let jwtSigner = JWTSigner.es256(privateKey: privKey)
122 | let signedJWT = try! myJWT.sign(using: jwtSigner)
123 | cloudConnect(jwtstring: signedJWT)
124 | }
125 |
126 |
127 | func cloudConnect(jwtstring:String) {
128 | mqtt = CocoaMQTT(clientID: "projects/{project-id}/locations/us-central1/registries/{registry-id}/devices/{device-id}", host: "mqtt.googleapis.com", port: 8883)
129 | mqtt!.username = ""
130 | mqtt!.password = jwtstring
131 | mqtt?.enableSSL = true
132 | mqtt?.keepAlive = 6000
133 | print(jwtstring)
134 | mqtt!.connect()
135 |
136 | DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
137 | self.mqtt?.subscribe("/devices/{device-id}}/commands/#", qos: CocoaMQTTQOS(rawValue: 1)!)
138 | self.mqtt?.subscribe("/devices/{device-id}/config", qos: CocoaMQTTQOS(rawValue: 1)!)
139 | print("Subscribed")
140 | }
141 |
142 | mqtt!.didReceiveMessage = { mqtt, message, id in
143 | print("Topic \(message.topic) : \(message.string!)")
144 |
145 | self.command = "\(message.topic) : \(message.string!)"
146 |
147 | if message.string! == "on" || message.string! == "off" {
148 | self.toggleFlash()
149 | }
150 | }
151 | }
152 |
153 |
154 | func publish() {
155 | mqtt?.publish("/devices/{device-id}/state", withString: "Connected")
156 |
157 | if(self.sensorData != ""){
158 | mqtt?.publish("/devices/{device-id}/events", withString: sensorData)
159 | }
160 | else{
161 | mqtt?.publish("/devices/{device-id}/events", withString: "Text Empty")
162 | }
163 |
164 | print("Published")
165 | }
166 |
167 |
168 | func toggleFlash() {
169 | guard let device = AVCaptureDevice.default(for: AVMediaType.video) else { return }
170 | guard device.hasTorch else { return }
171 |
172 | do {
173 | try device.lockForConfiguration()
174 |
175 | if (device.torchMode == AVCaptureDevice.TorchMode.on) {
176 | device.torchMode = AVCaptureDevice.TorchMode.off
177 | } else {
178 | do {
179 | try device.setTorchModeOn(level: 1.0)
180 | } catch {
181 | print(error)
182 | }
183 | }
184 |
185 | device.unlockForConfiguration()
186 | } catch {
187 | print(error)
188 | }
189 | }
190 |
191 |
192 | func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
193 |
194 | print(peripheral.name!)
195 | self.peripheral = peripheral
196 | self.peripheral?.delegate = self
197 |
198 | centralManager?.stopScan()
199 | centralManager?.connect(self.peripheral!)
200 | DispatchQueue.main.async { () -> Void in
201 | //ble connected
202 | };
203 | } // END func centralManager(... didDiscover peripheral
204 |
205 | func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
206 | self.peripheral?.discoverServices([serviceUUID])
207 | } // END func centralManager(... didConnect peripheral
208 |
209 |
210 | func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
211 | print("Disconnected!")
212 | DispatchQueue.main.async { () -> Void in
213 | // discconected
214 | };
215 | connected = false
216 | centralManager?.scanForPeripherals(withServices: [serviceUUID])
217 | } // END func centralManager(... didDisconnectPeripheral peripheral
218 |
219 |
220 | func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
221 | for service in peripheral.services! {
222 | if service.uuid == serviceUUID {
223 | peripheral.discoverCharacteristics(nil, for: service)
224 | }
225 | }
226 | } // END func peripheral(... didDiscoverServices
227 |
228 |
229 | func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
230 | for characteristic in service.characteristics! {
231 | if characteristic.uuid == readUUID {
232 | // Read how many bytes we should read from the esp32.
233 | peripheral.readValue(for: characteristic)
234 | } else if characteristic.uuid == dataUUID {
235 | dumpDataCharacteristic = characteristic
236 | }
237 | } // END for
238 | } // END func peripheral(... didDiscoverCharacteristicsFor service
239 |
240 |
241 | func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
242 |
243 | if characteristic.uuid == readUUID {
244 | let data = characteristic.value!
245 | let value = data.withUnsafeBytes { (ptr: UnsafePointer) -> UInt16 in
246 | return ptr.pointee
247 | }
248 | print("Should read \(value) bytes")
249 | size = value
250 | allData.removeAll()
251 |
252 | let dump = "dump".data(using: .utf8)!
253 | peripheral.writeValue(dump, for: dumpDataCharacteristic!, type: CBCharacteristicWriteType.withResponse)
254 | peripheral.setNotifyValue(true, for: dumpDataCharacteristic!)
255 |
256 | } else if characteristic.uuid == dataUUID {
257 | let data = characteristic.value!
258 | allData.append(data)
259 |
260 | DispatchQueue.main.async { () -> Void in
261 | if(self.connected == true){
262 | self.sensorData = String(decoding: characteristic.value!, as: UTF8.self)
263 | self.publish()
264 | }else{
265 | self.sensorData = ""
266 | }
267 | };
268 |
269 | if (allData.count >= size) {
270 | peripheral.setNotifyValue(true, for: dumpDataCharacteristic!)
271 | // We should verify the data.
272 | print("\n" + String(decoding: characteristic.value!, as: UTF8.self) + "\n")
273 | }
274 | } // END if characteristic.uuid ==...
275 | }
276 | }
277 |
--------------------------------------------------------------------------------