├── 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 | --------------------------------------------------------------------------------