├── .gitignore ├── images ├── edgecerts.png ├── m2bArduino4.png ├── m2bArduino5.png ├── m2bArduino6.png ├── m2bArduino7.png ├── m2bArduino8.png ├── m2bArduino9.png ├── create-iothub.png ├── edgeHubrunning.png ├── m2bArduino10.png ├── m2bArduino11.png ├── python_install.png ├── python_success.png ├── python_lib_busted.png └── IoT-Edge-Labs-Conceptual-Design.png ├── module2 ├── iothub_client_args.pyc ├── SourceModule │ ├── obj │ │ ├── Debug │ │ │ └── netcoreapp2.0 │ │ │ │ ├── SourceModule.AssemblyInfoInputs.cache │ │ │ │ ├── SourceModule.csproj.CoreCompileInputs.cache │ │ │ │ ├── SourceModule.dll │ │ │ │ ├── SourceModule.csproj.FileListAbsolute.txt │ │ │ │ └── SourceModule.AssemblyInfo.cs │ │ ├── SourceModule.csproj.nuget.cache │ │ ├── SourceModule.csproj.nuget.g.targets │ │ └── SourceModule.csproj.nuget.g.props │ ├── bin │ │ └── Debug │ │ │ └── netcoreapp2.0 │ │ │ ├── SourceModule.dll │ │ │ ├── publish │ │ │ ├── Validation.dll │ │ │ ├── SourceModule.dll │ │ │ ├── DotNetty.Codecs.dll │ │ │ ├── DotNetty.Common.dll │ │ │ ├── Newtonsoft.Json.dll │ │ │ ├── System.Spatial.dll │ │ │ ├── DotNetty.Buffers.dll │ │ │ ├── DotNetty.Handlers.dll │ │ │ ├── DotNetty.Transport.dll │ │ │ ├── Microsoft.Data.Edm.dll │ │ │ ├── DotNetty.Codecs.Mqtt.dll │ │ │ ├── Microsoft.Azure.Amqp.dll │ │ │ ├── Microsoft.Data.OData.dll │ │ │ ├── Microsoft.Extensions.Logging.dll │ │ │ ├── de │ │ │ │ ├── System.Spatial.resources.dll │ │ │ │ ├── Microsoft.Data.Edm.resources.dll │ │ │ │ └── Microsoft.Data.OData.resources.dll │ │ │ ├── es │ │ │ │ ├── System.Spatial.resources.dll │ │ │ │ ├── Microsoft.Data.Edm.resources.dll │ │ │ │ └── Microsoft.Data.OData.resources.dll │ │ │ ├── fr │ │ │ │ ├── System.Spatial.resources.dll │ │ │ │ ├── Microsoft.Data.Edm.resources.dll │ │ │ │ └── Microsoft.Data.OData.resources.dll │ │ │ ├── it │ │ │ │ ├── System.Spatial.resources.dll │ │ │ │ ├── Microsoft.Data.Edm.resources.dll │ │ │ │ └── Microsoft.Data.OData.resources.dll │ │ │ ├── ja │ │ │ │ ├── System.Spatial.resources.dll │ │ │ │ ├── Microsoft.Data.Edm.resources.dll │ │ │ │ └── Microsoft.Data.OData.resources.dll │ │ │ ├── ko │ │ │ │ ├── System.Spatial.resources.dll │ │ │ │ ├── Microsoft.Data.Edm.resources.dll │ │ │ │ └── Microsoft.Data.OData.resources.dll │ │ │ ├── ru │ │ │ │ ├── System.Spatial.resources.dll │ │ │ │ ├── Microsoft.Data.Edm.resources.dll │ │ │ │ └── Microsoft.Data.OData.resources.dll │ │ │ ├── Microsoft.Azure.Devices.Client.dll │ │ │ ├── Microsoft.Azure.Devices.Shared.dll │ │ │ ├── Microsoft.WindowsAzure.Storage.dll │ │ │ ├── Microsoft.Extensions.Primitives.dll │ │ │ ├── zh-Hans │ │ │ │ ├── System.Spatial.resources.dll │ │ │ │ ├── Microsoft.Data.Edm.resources.dll │ │ │ │ └── Microsoft.Data.OData.resources.dll │ │ │ ├── zh-Hant │ │ │ │ ├── System.Spatial.resources.dll │ │ │ │ ├── Microsoft.Data.Edm.resources.dll │ │ │ │ └── Microsoft.Data.OData.resources.dll │ │ │ ├── Microsoft.Extensions.Configuration.dll │ │ │ ├── System.Runtime.CompilerServices.Unsafe.dll │ │ │ ├── Microsoft.Extensions.Configuration.Json.dll │ │ │ ├── Microsoft.Extensions.FileSystemGlobbing.dll │ │ │ ├── Microsoft.Extensions.Configuration.Binder.dll │ │ │ ├── Microsoft.Extensions.FileProviders.Physical.dll │ │ │ ├── Microsoft.Extensions.Logging.Abstractions.dll │ │ │ ├── SourceModule.runtimeconfig.json │ │ │ ├── Microsoft.Extensions.Configuration.Abstractions.dll │ │ │ ├── Microsoft.Extensions.FileProviders.Abstractions.dll │ │ │ ├── Microsoft.Extensions.Configuration.FileExtensions.dll │ │ │ ├── Microsoft.Extensions.DependencyInjection.Abstractions.dll │ │ │ └── Microsoft.Extensions.Configuration.EnvironmentVariables.dll │ │ │ ├── SourceModule.runtimeconfig.json │ │ │ └── SourceModule.runtimeconfig.dev.json │ ├── Docker │ │ ├── linux-x64 │ │ │ ├── Dockerfile │ │ │ └── Dockerfile.debug │ │ └── windows-nano │ │ │ └── Dockerfile │ ├── .gitignore │ ├── SourceModule.csproj │ ├── deployment.json │ └── Program.cs ├── dotnet │ ├── readserial │ │ ├── obj │ │ │ ├── Debug │ │ │ │ └── netcoreapp2.0 │ │ │ │ │ ├── readserial.AssemblyInfoInputs.cache │ │ │ │ │ ├── serialdevice.AssemblyInfoInputs.cache │ │ │ │ │ ├── readserial.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── serialdevice.csproj.CoreCompileInputs.cache │ │ │ │ │ ├── readserial.dll │ │ │ │ │ ├── readserial.pdb │ │ │ │ │ ├── serialdevice.dll │ │ │ │ │ ├── serialdevice.pdb │ │ │ │ │ ├── readserial.csproj.FileListAbsolute.txt │ │ │ │ │ ├── serialdevice.csproj.FileListAbsolute.txt │ │ │ │ │ ├── readserial.AssemblyInfo.cs │ │ │ │ │ └── serialdevice.AssemblyInfo.cs │ │ │ ├── readserial.csproj.nuget.cache │ │ │ ├── serialdevice.csproj.nuget.cache │ │ │ ├── readserial.csproj.nuget.g.targets │ │ │ ├── serialdevice.csproj.nuget.g.targets │ │ │ ├── serialdevice.csproj.nuget.g.props │ │ │ └── readserial.csproj.nuget.g.props │ │ ├── bin │ │ │ └── Debug │ │ │ │ └── netcoreapp2.0 │ │ │ │ ├── readserial.dll │ │ │ │ ├── readserial.pdb │ │ │ │ ├── serialdevice.dll │ │ │ │ ├── serialdevice.pdb │ │ │ │ ├── readserial.runtimeconfig.json │ │ │ │ ├── serialdevice.runtimeconfig.json │ │ │ │ ├── readserial.runtimeconfig.dev.json │ │ │ │ └── serialdevice.runtimeconfig.dev.json │ │ ├── .vscode │ │ │ ├── tasks.json │ │ │ └── launch.json │ │ ├── readserial.csproj │ │ └── Program.cs │ └── readserial_nodevice │ │ ├── obj │ │ ├── Debug │ │ │ └── netcoreapp2.0 │ │ │ │ ├── readserial_nodevice.AssemblyInfoInputs.cache │ │ │ │ ├── readserial_nodevice.csproj.CoreCompileInputs.cache │ │ │ │ ├── readserial_nodevice.dll │ │ │ │ ├── readserial_nodevice.pdb │ │ │ │ ├── readserial_nodevice.csproj.FileListAbsolute.txt │ │ │ │ └── readserial_nodevice.AssemblyInfo.cs │ │ ├── readserial_nodevice.csproj.nuget.cache │ │ ├── readserial_nodevice.csproj.nuget.g.targets │ │ └── readserial_nodevice.csproj.nuget.g.props │ │ ├── bin │ │ └── Debug │ │ │ └── netcoreapp2.0 │ │ │ ├── readserial_nodevice.dll │ │ │ ├── readserial_nodevice.pdb │ │ │ ├── readserial_nodevice.runtimeconfig.json │ │ │ └── readserial_nodevice.runtimeconfig.dev.json │ │ ├── readserial_nodevice.csproj │ │ └── Program.cs ├── dhtSensorSketch │ └── dhtSensorSketch.ino ├── readserial.py ├── iothub_client_args.py ├── readserial_nodevice.py ├── README.dotnet.md └── README.md ├── .vscode ├── tasks.json └── launch.json ├── LICENSE.md ├── module4 ├── ASAWorkaround.md └── README.MD ├── README.md ├── troubleshooting.md ├── module1 └── README.md ├── module5 └── README.MD └── module3 └── README.MD /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.pyc 3 | *.cache 4 | *.cache 5 | *.props 6 | -------------------------------------------------------------------------------- /images/edgecerts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/edgecerts.png -------------------------------------------------------------------------------- /images/m2bArduino4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/m2bArduino4.png -------------------------------------------------------------------------------- /images/m2bArduino5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/m2bArduino5.png -------------------------------------------------------------------------------- /images/m2bArduino6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/m2bArduino6.png -------------------------------------------------------------------------------- /images/m2bArduino7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/m2bArduino7.png -------------------------------------------------------------------------------- /images/m2bArduino8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/m2bArduino8.png -------------------------------------------------------------------------------- /images/m2bArduino9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/m2bArduino9.png -------------------------------------------------------------------------------- /images/create-iothub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/create-iothub.png -------------------------------------------------------------------------------- /images/edgeHubrunning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/edgeHubrunning.png -------------------------------------------------------------------------------- /images/m2bArduino10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/m2bArduino10.png -------------------------------------------------------------------------------- /images/m2bArduino11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/m2bArduino11.png -------------------------------------------------------------------------------- /images/python_install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/python_install.png -------------------------------------------------------------------------------- /images/python_success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/python_success.png -------------------------------------------------------------------------------- /images/python_lib_busted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/python_lib_busted.png -------------------------------------------------------------------------------- /module2/iothub_client_args.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/iothub_client_args.pyc -------------------------------------------------------------------------------- /module2/SourceModule/obj/Debug/netcoreapp2.0/SourceModule.AssemblyInfoInputs.cache: -------------------------------------------------------------------------------- 1 | 191fedc1c179e39b18302f47480abbcac7bbe727 2 | -------------------------------------------------------------------------------- /module2/SourceModule/obj/Debug/netcoreapp2.0/SourceModule.csproj.CoreCompileInputs.cache: -------------------------------------------------------------------------------- 1 | e16b49714ade36253d105bb5d6b3011a8bac4d01 2 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/Debug/netcoreapp2.0/readserial.AssemblyInfoInputs.cache: -------------------------------------------------------------------------------- 1 | 46baf327a36e6672443b57f6ff13859e1bc80d32 2 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/Debug/netcoreapp2.0/serialdevice.AssemblyInfoInputs.cache: -------------------------------------------------------------------------------- 1 | e5a7b41c82857d45730692bf2df77565eaf131a9 2 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/Debug/netcoreapp2.0/readserial.csproj.CoreCompileInputs.cache: -------------------------------------------------------------------------------- 1 | 7b356ee8ebae21633dde312683f5c9454fccbb86 2 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/Debug/netcoreapp2.0/serialdevice.csproj.CoreCompileInputs.cache: -------------------------------------------------------------------------------- 1 | 0a8041bd1d2a9d0bb3e70ce3826c0f77e5bed368 2 | -------------------------------------------------------------------------------- /images/IoT-Edge-Labs-Conceptual-Design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/images/IoT-Edge-Labs-Conceptual-Design.png -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/obj/Debug/netcoreapp2.0/readserial_nodevice.AssemblyInfoInputs.cache: -------------------------------------------------------------------------------- 1 | ba100d1840e4c838ca272599c75b71613d89b70c 2 | -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/obj/Debug/netcoreapp2.0/readserial_nodevice.csproj.CoreCompileInputs.cache: -------------------------------------------------------------------------------- 1 | 380f8a2a830690bd09a1af4ba1cffd7a5a7ec7a7 2 | -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/SourceModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/SourceModule.dll -------------------------------------------------------------------------------- /module2/SourceModule/obj/Debug/netcoreapp2.0/SourceModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/obj/Debug/netcoreapp2.0/SourceModule.dll -------------------------------------------------------------------------------- /module2/dotnet/readserial/bin/Debug/netcoreapp2.0/readserial.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/dotnet/readserial/bin/Debug/netcoreapp2.0/readserial.dll -------------------------------------------------------------------------------- /module2/dotnet/readserial/bin/Debug/netcoreapp2.0/readserial.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/dotnet/readserial/bin/Debug/netcoreapp2.0/readserial.pdb -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/Debug/netcoreapp2.0/readserial.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/dotnet/readserial/obj/Debug/netcoreapp2.0/readserial.dll -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/Debug/netcoreapp2.0/readserial.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/dotnet/readserial/obj/Debug/netcoreapp2.0/readserial.pdb -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Validation.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Validation.dll -------------------------------------------------------------------------------- /module2/dotnet/readserial/bin/Debug/netcoreapp2.0/serialdevice.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/dotnet/readserial/bin/Debug/netcoreapp2.0/serialdevice.dll -------------------------------------------------------------------------------- /module2/dotnet/readserial/bin/Debug/netcoreapp2.0/serialdevice.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/dotnet/readserial/bin/Debug/netcoreapp2.0/serialdevice.pdb -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/Debug/netcoreapp2.0/serialdevice.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/dotnet/readserial/obj/Debug/netcoreapp2.0/serialdevice.dll -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/Debug/netcoreapp2.0/serialdevice.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/dotnet/readserial/obj/Debug/netcoreapp2.0/serialdevice.pdb -------------------------------------------------------------------------------- /module2/SourceModule/Docker/linux-x64/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/dotnet:2.0.0-runtime 2 | 3 | ARG EXE_DIR=. 4 | 5 | WORKDIR /app 6 | 7 | COPY $EXE_DIR/ ./ 8 | 9 | CMD ["dotnet", "SourceModule.dll"] -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/SourceModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/SourceModule.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/DotNetty.Codecs.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/DotNetty.Codecs.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/DotNetty.Common.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/DotNetty.Common.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/System.Spatial.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/System.Spatial.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/DotNetty.Buffers.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/DotNetty.Buffers.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/DotNetty.Handlers.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/DotNetty.Handlers.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/DotNetty.Transport.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/DotNetty.Transport.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Data.Edm.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Data.Edm.dll -------------------------------------------------------------------------------- /module2/SourceModule/Docker/windows-nano/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/dotnet:2.0.0-runtime-nanoserver-1709 2 | 3 | ARG EXE_DIR=. 4 | 5 | WORKDIR /app 6 | 7 | COPY $EXE_DIR/ ./ 8 | 9 | CMD ["dotnet", "SourceModule.dll"] -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/DotNetty.Codecs.Mqtt.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/DotNetty.Codecs.Mqtt.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Azure.Amqp.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Azure.Amqp.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Data.OData.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Data.OData.dll -------------------------------------------------------------------------------- /module2/SourceModule/obj/SourceModule.csproj.nuget.cache: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dgSpecHash": "CJaM0hJS7qwrl59t898n8/+AJ1gLGBdKSKd3t2nn3SE6l92E6G7Ce2SLhOGH/Gpx26lX4rNglv3QT0ybx8PXPw==", 4 | "success": true 5 | } -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/readserial.csproj.nuget.cache: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dgSpecHash": "bRxAs1z+18VU2PN2mfekQgxH2x7AkSHYwcphJtkXfVTZUeIEgxrxrPHuIFGwwK0NxN/Om5X+54z1HjBJnaWPXw==", 4 | "success": true 5 | } -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/serialdevice.csproj.nuget.cache: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dgSpecHash": "Pxao/CFuCN2GkzQFLt0LfyKD0KSNwIE3FfL5+c6tjt3qM3DKuZabJm25WMryVr00zVYQCvwV0E1IqgTXg2+tRg==", 4 | "success": true 5 | } -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/bin/Debug/netcoreapp2.0/readserial_nodevice.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/dotnet/readserial_nodevice/bin/Debug/netcoreapp2.0/readserial_nodevice.dll -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/bin/Debug/netcoreapp2.0/readserial_nodevice.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/dotnet/readserial_nodevice/bin/Debug/netcoreapp2.0/readserial_nodevice.pdb -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/obj/Debug/netcoreapp2.0/readserial_nodevice.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/dotnet/readserial_nodevice/obj/Debug/netcoreapp2.0/readserial_nodevice.dll -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/obj/Debug/netcoreapp2.0/readserial_nodevice.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/dotnet/readserial_nodevice/obj/Debug/netcoreapp2.0/readserial_nodevice.pdb -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Logging.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Logging.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/de/System.Spatial.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/de/System.Spatial.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/es/System.Spatial.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/es/System.Spatial.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/fr/System.Spatial.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/fr/System.Spatial.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/it/System.Spatial.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/it/System.Spatial.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ja/System.Spatial.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ja/System.Spatial.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ko/System.Spatial.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ko/System.Spatial.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ru/System.Spatial.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ru/System.Spatial.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Azure.Devices.Client.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Azure.Devices.Client.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Azure.Devices.Shared.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Azure.Devices.Shared.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.WindowsAzure.Storage.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.WindowsAzure.Storage.dll -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/obj/readserial_nodevice.csproj.nuget.cache: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dgSpecHash": "MoBMfUZYJZQ7WcHsYfmBkcBqKAaXwiJioh/2N1vd+dUq7jDMJWMYA202piohPyn88Lis3Nln/1dhVw6AHBWqwg==", 4 | "success": true 5 | } -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Primitives.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Primitives.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/de/Microsoft.Data.Edm.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/de/Microsoft.Data.Edm.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/de/Microsoft.Data.OData.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/de/Microsoft.Data.OData.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/es/Microsoft.Data.Edm.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/es/Microsoft.Data.Edm.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/es/Microsoft.Data.OData.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/es/Microsoft.Data.OData.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/fr/Microsoft.Data.Edm.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/fr/Microsoft.Data.Edm.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/fr/Microsoft.Data.OData.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/fr/Microsoft.Data.OData.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/it/Microsoft.Data.Edm.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/it/Microsoft.Data.Edm.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/it/Microsoft.Data.OData.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/it/Microsoft.Data.OData.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ja/Microsoft.Data.Edm.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ja/Microsoft.Data.Edm.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ja/Microsoft.Data.OData.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ja/Microsoft.Data.OData.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ko/Microsoft.Data.Edm.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ko/Microsoft.Data.Edm.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ko/Microsoft.Data.OData.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ko/Microsoft.Data.OData.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ru/Microsoft.Data.Edm.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ru/Microsoft.Data.Edm.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ru/Microsoft.Data.OData.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/ru/Microsoft.Data.OData.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/zh-Hans/System.Spatial.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/zh-Hans/System.Spatial.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/zh-Hant/System.Spatial.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/zh-Hant/System.Spatial.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Configuration.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Configuration.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/System.Runtime.CompilerServices.Unsafe.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/System.Runtime.CompilerServices.Unsafe.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/zh-Hans/Microsoft.Data.Edm.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/zh-Hans/Microsoft.Data.Edm.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/zh-Hans/Microsoft.Data.OData.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/zh-Hans/Microsoft.Data.OData.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/zh-Hant/Microsoft.Data.Edm.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/zh-Hant/Microsoft.Data.Edm.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/zh-Hant/Microsoft.Data.OData.resources.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/zh-Hant/Microsoft.Data.OData.resources.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/SourceModule.runtimeconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "tfm": "netcoreapp2.0", 4 | "framework": { 5 | "name": "Microsoft.NETCore.App", 6 | "version": "2.0.0" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Configuration.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Configuration.Json.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.FileSystemGlobbing.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.FileSystemGlobbing.dll -------------------------------------------------------------------------------- /module2/dotnet/readserial/bin/Debug/netcoreapp2.0/readserial.runtimeconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "tfm": "netcoreapp2.0", 4 | "framework": { 5 | "name": "Microsoft.NETCore.App", 6 | "version": "2.0.0" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Configuration.Binder.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Configuration.Binder.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.FileProviders.Physical.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.FileProviders.Physical.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Logging.Abstractions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Logging.Abstractions.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/SourceModule.runtimeconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "tfm": "netcoreapp2.0", 4 | "framework": { 5 | "name": "Microsoft.NETCore.App", 6 | "version": "2.0.0" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /module2/dotnet/readserial/bin/Debug/netcoreapp2.0/serialdevice.runtimeconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "tfm": "netcoreapp2.0", 4 | "framework": { 5 | "name": "Microsoft.NETCore.App", 6 | "version": "2.0.0" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Configuration.Abstractions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Configuration.Abstractions.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.FileProviders.Abstractions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.FileProviders.Abstractions.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Configuration.FileExtensions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Configuration.FileExtensions.dll -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/bin/Debug/netcoreapp2.0/readserial_nodevice.runtimeconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "tfm": "netcoreapp2.0", 4 | "framework": { 5 | "name": "Microsoft.NETCore.App", 6 | "version": "2.0.0" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.DependencyInjection.Abstractions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.DependencyInjection.Abstractions.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Configuration.EnvironmentVariables.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tikyau/azure-iot-edge-hol/master/module2/SourceModule/bin/Debug/netcoreapp2.0/publish/Microsoft.Extensions.Configuration.EnvironmentVariables.dll -------------------------------------------------------------------------------- /module2/SourceModule/bin/Debug/netcoreapp2.0/SourceModule.runtimeconfig.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "additionalProbingPaths": [ 4 | "C:\\Users\\stevebus\\.dotnet\\store\\|arch|\\|tfm|", 5 | "C:\\Users\\stevebus\\.nuget\\packages", 6 | "C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder" 7 | ] 8 | } 9 | } -------------------------------------------------------------------------------- /module2/dotnet/readserial/bin/Debug/netcoreapp2.0/readserial.runtimeconfig.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "additionalProbingPaths": [ 4 | "C:\\Users\\stevebus\\.dotnet\\store\\|arch|\\|tfm|", 5 | "C:\\Users\\stevebus\\.nuget\\packages", 6 | "C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder" 7 | ] 8 | } 9 | } -------------------------------------------------------------------------------- /module2/dotnet/readserial/bin/Debug/netcoreapp2.0/serialdevice.runtimeconfig.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "additionalProbingPaths": [ 4 | "C:\\Users\\stevebus\\.dotnet\\store\\|arch|\\|tfm|", 5 | "C:\\Users\\stevebus\\.nuget\\packages", 6 | "C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder" 7 | ] 8 | } 9 | } -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/bin/Debug/netcoreapp2.0/readserial_nodevice.runtimeconfig.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "additionalProbingPaths": [ 4 | "C:\\Users\\stevebus\\.dotnet\\store\\|arch|\\|tfm|", 5 | "C:\\Users\\stevebus\\.nuget\\packages", 6 | "C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder" 7 | ] 8 | } 9 | } -------------------------------------------------------------------------------- /module2/SourceModule/Docker/linux-x64/Dockerfile.debug: -------------------------------------------------------------------------------- 1 | FROM microsoft/dotnet:2.0.0-runtime 2 | 3 | ARG EXE_DIR=. 4 | 5 | WORKDIR /app 6 | 7 | COPY $EXE_DIR/ ./ 8 | 9 | RUN apt-get update 10 | 11 | RUN apt-get install -y unzip procps 12 | 13 | RUN curl -sSL https://aka.ms/getvsdbgsh | bash /dev/stdin -v latest -l ~/vsdbg 14 | 15 | CMD ["dotnet", "SourceModule.dll"] -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/readserial_nodevice.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.0 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "taskName": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/module2/dotnet/readserial/readserial.csproj" 11 | ], 12 | "problemMatcher": "$msCompile" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /module2/dotnet/readserial/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "taskName": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/serialdevice.csproj" 11 | ], 12 | "problemMatcher": "$msCompile" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /module2/SourceModule/.gitignore: -------------------------------------------------------------------------------- 1 | # .NET Core 2 | project.lock.json 3 | project.fragment.lock.json 4 | artifacts/ 5 | **/Properties/launchSettings.json 6 | 7 | *_i.c 8 | *_p.c 9 | *_i.h 10 | *.ilk 11 | *.meta 12 | *.obj 13 | *.pch 14 | *.pdb 15 | *.pgc 16 | *.pgd 17 | *.rsp 18 | *.sbr 19 | *.tlb 20 | *.tli 21 | *.tlh 22 | *.tmp 23 | *.tmp_proj 24 | *.log 25 | *.vspscc 26 | *.vssscc 27 | .builds 28 | *.pidb 29 | *.svclog 30 | *.scc 31 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/readserial.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/Debug/netcoreapp2.0/readserial.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | C:\serial\readserial\bin\Debug\netcoreapp2.0\readserial.deps.json 2 | C:\serial\readserial\bin\Debug\netcoreapp2.0\readserial.runtimeconfig.json 3 | C:\serial\readserial\bin\Debug\netcoreapp2.0\readserial.runtimeconfig.dev.json 4 | C:\serial\readserial\bin\Debug\netcoreapp2.0\readserial.dll 5 | C:\serial\readserial\bin\Debug\netcoreapp2.0\readserial.pdb 6 | C:\serial\readserial\obj\Debug\netcoreapp2.0\readserial.csproj.CoreCompileInputs.cache 7 | C:\serial\readserial\obj\Debug\netcoreapp2.0\readserial.AssemblyInfoInputs.cache 8 | C:\serial\readserial\obj\Debug\netcoreapp2.0\readserial.AssemblyInfo.cs 9 | C:\serial\readserial\obj\Debug\netcoreapp2.0\readserial.dll 10 | C:\serial\readserial\obj\Debug\netcoreapp2.0\readserial.pdb 11 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/Debug/netcoreapp2.0/serialdevice.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | C:\serial\serialdevice\bin\Debug\netcoreapp2.0\serialdevice.deps.json 2 | C:\serial\serialdevice\bin\Debug\netcoreapp2.0\serialdevice.runtimeconfig.json 3 | C:\serial\serialdevice\bin\Debug\netcoreapp2.0\serialdevice.runtimeconfig.dev.json 4 | C:\serial\serialdevice\bin\Debug\netcoreapp2.0\serialdevice.dll 5 | C:\serial\serialdevice\bin\Debug\netcoreapp2.0\serialdevice.pdb 6 | C:\serial\serialdevice\obj\Debug\netcoreapp2.0\serialdevice.csproj.CoreCompileInputs.cache 7 | C:\serial\serialdevice\obj\Debug\netcoreapp2.0\serialdevice.AssemblyInfoInputs.cache 8 | C:\serial\serialdevice\obj\Debug\netcoreapp2.0\serialdevice.AssemblyInfo.cs 9 | C:\serial\serialdevice\obj\Debug\netcoreapp2.0\serialdevice.dll 10 | C:\serial\serialdevice\obj\Debug\netcoreapp2.0\serialdevice.pdb 11 | -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/obj/Debug/netcoreapp2.0/readserial_nodevice.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | C:\serial\readserial_nodevice\obj\Debug\netcoreapp2.0\readserial_nodevice.csproj.CoreCompileInputs.cache 2 | C:\serial\readserial_nodevice\obj\Debug\netcoreapp2.0\readserial_nodevice.AssemblyInfoInputs.cache 3 | C:\serial\readserial_nodevice\obj\Debug\netcoreapp2.0\readserial_nodevice.AssemblyInfo.cs 4 | C:\serial\readserial_nodevice\bin\Debug\netcoreapp2.0\readserial_nodevice.deps.json 5 | C:\serial\readserial_nodevice\bin\Debug\netcoreapp2.0\readserial_nodevice.runtimeconfig.json 6 | C:\serial\readserial_nodevice\bin\Debug\netcoreapp2.0\readserial_nodevice.runtimeconfig.dev.json 7 | C:\serial\readserial_nodevice\bin\Debug\netcoreapp2.0\readserial_nodevice.dll 8 | C:\serial\readserial_nodevice\bin\Debug\netcoreapp2.0\readserial_nodevice.pdb 9 | C:\serial\readserial_nodevice\obj\Debug\netcoreapp2.0\readserial_nodevice.dll 10 | C:\serial\readserial_nodevice\obj\Debug\netcoreapp2.0\readserial_nodevice.pdb 11 | -------------------------------------------------------------------------------- /module2/SourceModule/obj/SourceModule.csproj.nuget.g.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/readserial.csproj.nuget.g.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/serialdevice.csproj.nuget.g.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/obj/readserial_nodevice.csproj.nuget.g.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /module2/SourceModule/obj/Debug/netcoreapp2.0/SourceModule.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | c:\Users\stevebus\Documents\edge\SourceModule\bin\Debug\netcoreapp2.0\SourceModule.deps.json 2 | c:\Users\stevebus\Documents\edge\SourceModule\bin\Debug\netcoreapp2.0\SourceModule.runtimeconfig.json 3 | c:\Users\stevebus\Documents\edge\SourceModule\bin\Debug\netcoreapp2.0\SourceModule.runtimeconfig.dev.json 4 | c:\Users\stevebus\Documents\edge\SourceModule\bin\Debug\netcoreapp2.0\SourceModule.dll 5 | c:\Users\stevebus\Documents\edge\SourceModule\bin\Debug\netcoreapp2.0\SourceModule.pdb 6 | c:\Users\stevebus\Documents\edge\SourceModule\obj\Debug\netcoreapp2.0\SourceModule.csproj.CoreCompileInputs.cache 7 | c:\Users\stevebus\Documents\edge\SourceModule\obj\Debug\netcoreapp2.0\SourceModule.AssemblyInfoInputs.cache 8 | c:\Users\stevebus\Documents\edge\SourceModule\obj\Debug\netcoreapp2.0\SourceModule.AssemblyInfo.cs 9 | c:\Users\stevebus\Documents\edge\SourceModule\obj\Debug\netcoreapp2.0\SourceModule.dll 10 | c:\Users\stevebus\Documents\edge\SourceModule\obj\Debug\netcoreapp2.0\SourceModule.pdb 11 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/Debug/netcoreapp2.0/readserial.AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | using System; 12 | using System.Reflection; 13 | 14 | [assembly: System.Reflection.AssemblyCompanyAttribute("readserial")] 15 | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 16 | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 17 | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] 18 | [assembly: System.Reflection.AssemblyProductAttribute("readserial")] 19 | [assembly: System.Reflection.AssemblyTitleAttribute("readserial")] 20 | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] 21 | 22 | // Generated by the MSBuild WriteCodeFragment class. 23 | 24 | -------------------------------------------------------------------------------- /module2/SourceModule/obj/Debug/netcoreapp2.0/SourceModule.AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | using System; 12 | using System.Reflection; 13 | 14 | [assembly: System.Reflection.AssemblyCompanyAttribute("SourceModule")] 15 | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 16 | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 17 | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] 18 | [assembly: System.Reflection.AssemblyProductAttribute("SourceModule")] 19 | [assembly: System.Reflection.AssemblyTitleAttribute("SourceModule")] 20 | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] 21 | 22 | // Generated by the MSBuild WriteCodeFragment class. 23 | 24 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/Debug/netcoreapp2.0/serialdevice.AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | using System; 12 | using System.Reflection; 13 | 14 | [assembly: System.Reflection.AssemblyCompanyAttribute("serialdevice")] 15 | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 16 | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 17 | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] 18 | [assembly: System.Reflection.AssemblyProductAttribute("serialdevice")] 19 | [assembly: System.Reflection.AssemblyTitleAttribute("serialdevice")] 20 | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] 21 | 22 | // Generated by the MSBuild WriteCodeFragment class. 23 | 24 | -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/obj/Debug/netcoreapp2.0/readserial_nodevice.AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | using System; 12 | using System.Reflection; 13 | 14 | [assembly: System.Reflection.AssemblyCompanyAttribute("readserial_nodevice")] 15 | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 16 | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 17 | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] 18 | [assembly: System.Reflection.AssemblyProductAttribute("readserial_nodevice")] 19 | [assembly: System.Reflection.AssemblyTitleAttribute("readserial_nodevice")] 20 | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] 21 | 22 | // Generated by the MSBuild WriteCodeFragment class. 23 | 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE -------------------------------------------------------------------------------- /module2/dotnet/readserial/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to find out which attributes exist for C# debugging 3 | // Use hover for the description of the existing attributes 4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Launch (console)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/bin/Debug/netcoreapp2.0/serialdevice.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}", 16 | // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window 17 | "console": "internalConsole", 18 | "stopAtEntry": false, 19 | "internalConsoleOptions": "openOnSessionStart" 20 | }, 21 | { 22 | "name": ".NET Core Attach", 23 | "type": "coreclr", 24 | "request": "attach", 25 | "processId": "${command:pickProcess}" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /module2/SourceModule/SourceModule.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | netcoreapp2.0 5 | 6 | 7 | 8 | True 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to find out which attributes exist for C# debugging 3 | // Use hover for the description of the existing attributes 4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Launch (console)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/module2/dotnet/readserial/bin/Debug/netcoreapp2.0/readserial.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}/module2/dotnet/readserial", 16 | // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window 17 | "console": "internalConsole", 18 | "stopAtEntry": false, 19 | "internalConsoleOptions": "openOnSessionStart" 20 | }, 21 | { 22 | "name": ".NET Core Attach", 23 | "type": "coreclr", 24 | "request": "attach", 25 | "processId": "${command:pickProcess}" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /module4/ASAWorkaround.md: -------------------------------------------------------------------------------- 1 | 2 | # Temporary ASA workaround 3 | 4 | This file documents the temporary ASA work around for stream analytics 5 | 6 | At this point, you should have just imported the ASA job. 7 | 8 | Before we continue, go to your command prompt and stop iotedge with: 9 | 10 | ``` 11 | iotedgectl stop 12 | ``` 13 | 14 | we will be pulling a "private" build of the ASA module from a container repository in azure. To do so, we need to provide the credentials to the repository so the Edge Agent can pull it. To do so, run the following command 15 | 16 | ``` 17 | iotedgectl login --address asaedgeregistry.azurecr.io --username asaedgeregistry --password 18 | ``` 19 | 20 | You will need the get the password for this repo from your lab instructor. 21 | 22 | Once done, we will delete the edgeAgent container and restart edge with 23 | 24 | ``` 25 | docker container rm -f edgeAgent 26 | iotedgectl start 27 | ``` 28 | 29 | Back on the Set Modules page, click on the ASA module you just imported. That should show the properties of the module, including among other things, the image URI (which will be something that looks like ````microsoft/azureiotedge-azure-stream-analytics:1.0.0-preview004````). 30 | 31 | update the image URI to be: 32 | 33 | ````asaedgeregistry.azurecr.io/asamodule:1.0.0-linux-amd64```` 34 | 35 | and click the Save button. 36 | 37 | Return to the preview instructions and continue with setting routes 38 | 39 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/serialdevice.csproj.nuget.g.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | True 5 | NuGet 6 | C:\serial\serialdevice\obj\project.assets.json 7 | $(UserProfile)\.nuget\packages\ 8 | C:\Users\stevebus\.nuget\packages\;C:\Program Files\dotnet\sdk\NuGetFallbackFolder 9 | PackageReference 10 | 4.5.0 11 | 12 | 13 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /module2/SourceModule/obj/SourceModule.csproj.nuget.g.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | True 5 | NuGet 6 | c:\azure-iot-edge-hol\module2\SourceModule\obj\project.assets.json 7 | $(UserProfile)\.nuget\packages\ 8 | C:\Users\stevebus\.nuget\packages\;C:\Program Files\dotnet\sdk\NuGetFallbackFolder 9 | PackageReference 10 | 4.5.0 11 | 12 | 13 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/obj/readserial.csproj.nuget.g.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | True 5 | NuGet 6 | c:\azure-iot-edge-hol\module2\dotnet\readserial\obj\project.assets.json 7 | $(UserProfile)\.nuget\packages\ 8 | C:\Users\stevebus\.nuget\packages\;C:\Program Files\dotnet\sdk\NuGetFallbackFolder 9 | PackageReference 10 | 4.5.0 11 | 12 | 13 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /module2/SourceModule/deployment.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleContent": { 3 | "$edgeAgent": { 4 | "properties.desired": { 5 | "schemaVersion": "1.0", 6 | "runtime": { 7 | "type": "docker", 8 | "settings": { 9 | "minDockerVersion": "v1.25", 10 | "loggingOptions": "" 11 | } 12 | }, 13 | "systemModules": { 14 | "edgeAgent": { 15 | "type": "docker", 16 | "settings": { 17 | "image": "microsoft/azureiotedge-agent:1.0-preview", 18 | "createOptions": "" 19 | } 20 | }, 21 | "edgeHub": { 22 | "type": "docker", 23 | "status": "running", 24 | "restartPolicy": "always", 25 | "settings": { 26 | "image": "microsoft/azureiotedge-hub:1.0-preview", 27 | "createOptions": "" 28 | } 29 | } 30 | }, 31 | "modules": { 32 | "SourceModule": { 33 | "version": "1.0", 34 | "type": "docker", 35 | "status": "running", 36 | "restartPolicy": "always", 37 | "settings": { 38 | "image": "/:", 39 | "createOptions": "{}" 40 | } 41 | } 42 | } 43 | } 44 | }, 45 | "$edgeHub": { 46 | "properties.desired": { 47 | "schemaVersion": "1.0", 48 | "routes": { 49 | "route": "FROM /* INTO $upstream" 50 | }, 51 | "storeAndForwardConfiguration": { 52 | "timeToLiveSecs": 7200 53 | } 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/obj/readserial_nodevice.csproj.nuget.g.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | True 5 | NuGet 6 | c:\azure-iot-edge-hol\module2\dotnet\readserial_nodevice\obj\project.assets.json 7 | $(UserProfile)\.nuget\packages\ 8 | C:\Users\stevebus\.nuget\packages\;C:\Program Files\dotnet\sdk\NuGetFallbackFolder 9 | PackageReference 10 | 4.5.0 11 | 12 | 13 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /module2/dhtSensorSketch/dhtSensorSketch.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #define DHTTYPE DHT22 3 | 4 | //Set’s the pin we’re reading data from and initializes the sensor. 5 | int DHTPIN = 2; 6 | DHT dht(DHTPIN,DHTTYPE); 7 | 8 | String inputString = ""; // a string to hold incoming data 9 | boolean stringComplete = false; // whether the string is complete 10 | 11 | #define pinLED 13 // pin 13 is the onboard LED 12 | 13 | void setup() { 14 | //Tell the arduino we’ll be reading data on the defined DHT pin 15 | pinMode(DHTPIN, INPUT); 16 | 17 | //Open the serial port for communication 18 | Serial.begin(9600); 19 | 20 | //start the connection for reading. 21 | dht.begin(); 22 | 23 | // we will be 'writing' to the pin, vs. reading 24 | pinMode(pinLED, OUTPUT); 25 | // start with the LED off 26 | digitalWrite(pinLED, LOW); 27 | 28 | } 29 | 30 | void loop() { 31 | //declare variables for storing temperature and humidity and capture 32 | float h = dht.readHumidity(); 33 | float t = dht.readTemperature(true); 34 | 35 | //output data as humidity,temperature 36 | Serial.print(h); 37 | Serial.print(","); 38 | Serial.println(t); //println includes linefeed 39 | 40 | serialEvent(); //call the function to read any command in the serial buffer 41 | // print the string when a newline arrives: 42 | if (stringComplete) { 43 | // Serial.println(inputString); 44 | 45 | // turn LED on or off depending on command 46 | if(inputString == "OFF") 47 | digitalWrite(pinLED, LOW); 48 | if(inputString == "ON") 49 | digitalWrite(pinLED, HIGH); 50 | 51 | // clear the string: 52 | inputString = ""; 53 | stringComplete = false; 54 | } 55 | 56 | //sleep for two seconds before reading again 57 | delay(2000); 58 | } 59 | 60 | 61 | 62 | void serialEvent() { 63 | // while there is data to read in the buffer, read it 64 | while (Serial.available()) { 65 | // get the new byte: 66 | char inChar = (char)Serial.read(); 67 | // add it to the inputString. if it's a newline, bail as that completes the message 68 | if (inChar == '\n') { 69 | stringComplete = true; 70 | } 71 | else 72 | inputString += inChar; 73 | } 74 | } -------------------------------------------------------------------------------- /module2/readserial.py: -------------------------------------------------------------------------------- 1 | import serial 2 | import time 3 | 4 | import iothub_client 5 | from iothub_client import * 6 | from iothub_client_args import * 7 | 8 | i = 0 9 | 10 | #change this to your specifics... (e.g. "COM3") 11 | ser = serial.Serial('', 9600) 12 | 13 | #change this -- don't forget the "GatewayHostName" param at the end 14 | connection_string = "" 15 | 16 | def receive_message_callback(message, counter): 17 | buffer = message.get_bytearray() 18 | size = len(buffer) 19 | msg = buffer[:size].decode('utf-8') 20 | print("received C2D command {%s}" % (msg)) 21 | return IoTHubMessageDispositionResult.ACCEPTED 22 | 23 | def device_method_callback(method_name, payload, user_context): 24 | print("received DM {%s}, payload: %s" % (method_name, payload)) 25 | 26 | if("ON" in str(method_name)): 27 | print("ON method called") 28 | ser.write('ON\n') 29 | ser.flush() 30 | 31 | if("OFF" in str(method_name)): 32 | print("OFF method called") 33 | ser.write('OFF\n') 34 | ser.flush() 35 | 36 | device_method_return_value = DeviceMethodReturnValue() 37 | device_method_return_value.response = "{ \"Response\": \"This is the response from the device\" }" 38 | device_method_return_value.status = 200 39 | return device_method_return_value 40 | 41 | def device_twin_callback(update_state, payload, user_context): 42 | print("Device Twin update %s... %s" % (update_state, payload)) 43 | 44 | protocol = IoTHubTransportProvider.MQTT 45 | 46 | iotHubClient = IoTHubClient(connection_string, protocol) 47 | print("Connected to IoTHub gateway") 48 | 49 | iotHubClient.set_device_twin_callback(device_twin_callback, 0) 50 | iotHubClient.set_device_method_callback(device_method_callback, 0) 51 | iotHubClient.set_message_callback(receive_message_callback, 0) 52 | 53 | def send_confirmation_callback(message, result, user_context): 54 | global i 55 | print("message number %d sent " % (user_context)) 56 | return 57 | 58 | while 1: 59 | serial_line = ser.readline().strip() 60 | print(serial_line) 61 | 62 | # serial_line="22.22,33.33" 63 | 64 | message = IoTHubMessage(bytearray(serial_line, 'utf8')) 65 | iotHubClient.send_event_async(message, send_confirmation_callback, i) 66 | 67 | i=i+1 68 | 69 | # time.sleep(2) 70 | 71 | ser.close() # Only executes once the loop exits 72 | 73 | -------------------------------------------------------------------------------- /module2/iothub_client_args.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft. All rights reserved. 2 | # Licensed under the MIT license. See LICENSE file in the project root for 3 | # full license information. 4 | 5 | import getopt 6 | from iothub_client import * 7 | #IoTHubTransportProvider 8 | 9 | 10 | class OptionError(Exception): 11 | 12 | def __init__(self, value): 13 | self.value = value 14 | 15 | def __str__(self): 16 | return repr(self.value) 17 | 18 | 19 | def get_iothub_opt( 20 | argv, 21 | connection_string, 22 | protocol=IoTHubTransportProvider.MQTT): 23 | if len(argv) > 0: 24 | try: 25 | opts, args = getopt.getopt( 26 | argv, "hp:c:", [ 27 | "protocol=", "connectionstring="]) 28 | except getopt.GetoptError as opt_error: 29 | raise OptionError("Error: %s" % opt_error.msg) 30 | for opt, arg in opts: 31 | if opt == '-h': 32 | raise OptionError("Help:") 33 | elif opt in ("-p", "--protocol"): 34 | protocol_string = arg.lower() 35 | 36 | if protocol_string == "http": 37 | if hasattr(IoTHubTransportProvider, "HTTP"): 38 | protocol = IoTHubTransportProvider.HTTP 39 | else: 40 | raise OptionError("Error: HTTP protocol is not supported") 41 | 42 | elif protocol_string == "amqp": 43 | if hasattr(IoTHubTransportProvider, "AMQP"): 44 | protocol = IoTHubTransportProvider.AMQP 45 | else: 46 | raise OptionError("Error: AMQP protocol is not supported") 47 | 48 | elif protocol_string == "amqp_ws": 49 | if hasattr(IoTHubTransportProvider, "AMQP_WS"): 50 | protocol = IoTHubTransportProvider.AMQP_WS 51 | else: 52 | raise OptionError("Error: AMQP_WS protocol is not supported") 53 | 54 | elif protocol_string == "mqtt": 55 | if hasattr(IoTHubTransportProvider, "MQTT"): 56 | protocol = IoTHubTransportProvider.MQTT 57 | else: 58 | raise OptionError("Error: MQTT protocol is not supported") 59 | 60 | elif hasattr(IoTHubTransportProvider, "MQTT_WS"): 61 | if hasattr(IoTHubTransportProvider, "MQTT_WS"): 62 | protocol = IoTHubTransportProvider.MQTT_WS 63 | else: 64 | raise OptionError("Error: MQTT_WS protocol is not supported") 65 | else: 66 | raise OptionError( 67 | "Error: unknown protocol %s" % 68 | protocol_string) 69 | elif opt in ("-c", "--connectionstring"): 70 | connection_string = arg 71 | 72 | if connection_string.find("HostName") < 0: 73 | raise OptionError( 74 | "Error: Hostname not found, not a valid connection string") 75 | 76 | return connection_string, protocol -------------------------------------------------------------------------------- /module2/readserial_nodevice.py: -------------------------------------------------------------------------------- 1 | #import serial 2 | import time 3 | 4 | import iothub_client 5 | from iothub_client import * 6 | from iothub_client_args import * 7 | 8 | i = 0 9 | 10 | #set min and maxes for temperature and humidity 11 | min_temp = 70.0 12 | max_temp = 90.0 13 | min_humidity = 50.0 14 | max_humidity = 60.0 15 | valley_to_peak_samples = 30 16 | 17 | #change this -- don't forget the "GatewayHostName" param at the end 18 | connection_string = "" 19 | 20 | # directions for simulated data 21 | temp_going_up = True 22 | humidity_going_up = True 23 | last_temp = min_temp 24 | last_humidity = min_humidity 25 | temp_range = (max_temp - min_temp) / valley_to_peak_samples 26 | humidity_range = (max_humidity - min_humidity) / valley_to_peak_samples 27 | 28 | def receive_message_callback(message, counter): 29 | buffer = message.get_bytearray() 30 | size = len(buffer) 31 | msg = buffer[:size].decode('utf-8') 32 | print("received C2D command {%s}" % (msg)) 33 | return IoTHubMessageDispositionResult.ACCEPTED 34 | 35 | def device_method_callback(method_name, payload, user_context): 36 | print("received DM {%s}, payload: %s" % (method_name, payload)) 37 | 38 | device_method_return_value = DeviceMethodReturnValue() 39 | device_method_return_value.response = "{ \"Response\": \"This is the response from the device\" }" 40 | device_method_return_value.status = 200 41 | return device_method_return_value 42 | 43 | def device_twin_callback(update_state, payload, user_context): 44 | print("Device Twin update %s... %s" % (update_state, payload)) 45 | 46 | protocol = IoTHubTransportProvider.MQTT 47 | 48 | iotHubClient = IoTHubClient(connection_string, protocol) 49 | print("Connected to IoTHub gateway") 50 | 51 | iotHubClient.set_device_twin_callback(device_twin_callback, 0) 52 | iotHubClient.set_device_method_callback(device_method_callback, 0) 53 | iotHubClient.set_message_callback(receive_message_callback, 0) 54 | 55 | def send_confirmation_callback(message, result, user_context): 56 | global i 57 | print(" message number %d sent " % (user_context)) 58 | return 59 | 60 | def GetNextTemp(): 61 | global min_temp 62 | global max_temp 63 | global last_temp 64 | global temp_going_up 65 | global temp_range 66 | 67 | if(temp_going_up): 68 | curr_temp = last_temp + temp_range 69 | if(curr_temp > max_temp): 70 | curr_temp = max_temp 71 | temp_going_up = False 72 | else: 73 | curr_temp = last_temp - temp_range 74 | if(curr_temp < min_temp): 75 | curr_temp = min_temp 76 | temp_going_up = True 77 | 78 | last_temp = curr_temp 79 | return curr_temp 80 | 81 | def GetNextHumidity(): 82 | global min_humidity 83 | global max_humidity 84 | global last_humidity 85 | global humidity_going_up 86 | global humidity_range 87 | 88 | if(humidity_going_up): 89 | curr_humidity = last_humidity + humidity_range 90 | if(curr_humidity > max_humidity): 91 | curr_humidity = max_humidity 92 | humidity_going_up = False 93 | else: 94 | curr_humidity = last_humidity - humidity_range 95 | if(curr_humidity < min_humidity): 96 | curr_humidity = min_humidity 97 | humidity_going_up = True 98 | 99 | last_humidity = curr_humidity 100 | return curr_humidity 101 | 102 | 103 | while 1: 104 | # serial_line = ser.readline() 105 | # print(serial_line) 106 | 107 | curr_temp = GetNextTemp() 108 | curr_humidity = GetNextHumidity() 109 | 110 | serial_line_template = "%2.2f,%2.2f" 111 | serial_line= serial_line_template % (curr_humidity, curr_temp) 112 | 113 | message = IoTHubMessage(bytearray(serial_line, 'utf8')) 114 | iotHubClient.send_event_async(message, send_confirmation_callback, i) 115 | 116 | print("sending message: [%s]" % (serial_line)) 117 | 118 | i=i+1 119 | 120 | time.sleep(2) 121 | 122 | #ser.close() # Only executes once the loop exits 123 | 124 | -------------------------------------------------------------------------------- /module2/dotnet/readserial/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO.Ports; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Microsoft.Azure.Devices.Client; 6 | using Microsoft.Azure.Devices.Client.Transport.Mqtt; 7 | using Microsoft.Azure.Devices.Shared; 8 | 9 | namespace readserial 10 | { 11 | class Program 12 | { 13 | 14 | static string PortName = ""; // e.g. "COM3" 15 | static string ConnectionString = ""; //don't forget the ;GatewayHostName=mygateway.local 16 | 17 | static bool _continue; 18 | static SerialPort _serialPort; 19 | 20 | static DeviceClient _deviceClient; 21 | 22 | static int counter = 0; 23 | 24 | static void Main(string[] args) 25 | { 26 | Thread readThread = new Thread(Read); 27 | 28 | InitDeviceClient().Wait(); 29 | 30 | _serialPort = new SerialPort(); 31 | 32 | // Allow the user to set the appropriate properties. 33 | _serialPort.PortName = PortName; 34 | _serialPort.BaudRate = 9600; 35 | _serialPort.Parity = Parity.None; 36 | _serialPort.DataBits = 8; 37 | _serialPort.StopBits = StopBits.One; 38 | _serialPort.Handshake = Handshake.None; 39 | 40 | // Set the read/write timeouts 41 | _serialPort.ReadTimeout = 500; 42 | _serialPort.WriteTimeout = 500; 43 | 44 | _serialPort.Open(); 45 | Console.WriteLine($"Serial port [{PortName}] opened"); 46 | 47 | _continue = true; 48 | readThread.Start(); 49 | 50 | Console.WriteLine("press to exit"); 51 | 52 | Console.ReadLine(); 53 | 54 | _continue = false; 55 | 56 | readThread.Join(); 57 | _serialPort.Close(); 58 | //_deviceClient.Close(); 59 | 60 | } 61 | 62 | static Task HandleDirectMethod(MethodRequest methodRequest, object userContext) 63 | { 64 | Console.WriteLine($"Direct Method ({methodRequest.Name}) invoked... "); 65 | // Console.WriteLine("\t{0}", methodRequest.DataAsJson); 66 | Console.WriteLine("\nReturning response for method {0}", methodRequest.Name); 67 | 68 | writeSerial(methodRequest.Name); 69 | 70 | string result = "'Input was written to log.'"; 71 | return Task.FromResult(new MethodResponse(System.Text.Encoding.UTF8.GetBytes(result), 200)); 72 | } 73 | 74 | static void writeSerial(string command) 75 | { 76 | _serialPort.WriteLine(command); 77 | } 78 | 79 | static public async Task InitDeviceClient() 80 | { 81 | MqttTransportSettings mqttSetting = new MqttTransportSettings(TransportType.Mqtt_Tcp_Only); 82 | // During dev you might want to bypass the cert verification. It is highly recommended to verify certs systematically in production 83 | mqttSetting.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; 84 | ITransportSettings[] settings = { mqttSetting }; 85 | 86 | _deviceClient = DeviceClient.CreateFromConnectionString(ConnectionString, settings); 87 | await _deviceClient.OpenAsync(); 88 | Console.WriteLine($"Connected to IoT Edge with connection string [{ConnectionString}]"); 89 | 90 | _deviceClient.SetMethodHandlerAsync("ON", HandleDirectMethod, null).Wait(); 91 | _deviceClient.SetMethodHandlerAsync("OFF", HandleDirectMethod, null).Wait(); 92 | 93 | } 94 | 95 | public static void Read() 96 | { 97 | while (_continue) 98 | { 99 | try 100 | { 101 | string message = _serialPort.ReadLine().Trim(); 102 | // Console.WriteLine(message); 103 | var mess = new Message(System.Text.Encoding.ASCII.GetBytes(message)); 104 | 105 | // await _deviceClient.SendEventAsync("output1", mess); 106 | Task t = _deviceClient.SendEventAsync(mess); 107 | Console.WriteLine($"Message sent({counter++}) {message}"); 108 | } 109 | catch (TimeoutException) { } 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Azure IoT Edge Hands On Labs 2 | 3 | Created and maintained by the Microsoft Azure IoT Global Black Belts 4 | 5 | # NOTE - We are in the process of updating the labs to leverage the new GA bits and process for IoT Edge... We hope to have the updates soon. Currently, consider these labs "closed for construction" :-) 6 | 7 | ## Overview 8 | 9 | This hands-on lab demonstrates setting up, configuring, and developing modules for [Azure IoT Edge](https://azure.microsoft.com/en-us/services/iot-edge/). The intent of these labs is not to cover exhaustively every IoT Edge topic, but rather cover a scenario that allows the student to learn and understand the basics of IoT Edge, develop modules and Edge ASA jobs, and perform Edge configuration, all in a pseudo-realistic use case. 10 | 11 | These labs were originally developed to be delivered in-person by the Azure IoT GBBs to customers, however, they are available for any customers or partners to leverage, to play, or to learn. Over time, they will evolve past this original use to incorporate other use cases. 12 | 13 | In this workshop you will: 14 | 15 | * Setup and configure a simple IoT Device, based on an Arduino Uno connected to a DHT22 temperature sensor, to simply (and dumbly) send temperature over the serial port every 3 seconds 16 | * create an "IoT Device" that reads the data from the serial port and connects to IoT Hub __**through**__ IoT Edge 17 | * create an IoT Edge module that reads the simple CSV temp/humidity data from the device and converts to JSON and passes the message along 18 | * create an Azure Stream Analytics module that a) aggregates the "every 3 seconds" data to a 30 second frequency to send to IoT Hub in the cloud and b) looks for temperatures above a certain threshold. When a threshold violation occurs, the module will drop an "alert" message on Edge 19 | * create an IoT Edge module that reads the "alert" message from ASA and sends a Direct Method call to the IoT Device to light up an "alert" LED 20 | 21 | The labs are broken up into the following modules: 22 | 23 | * [Module 1](module1) - Prerequisites and IoT Edge setup 24 | * [Module 2](module2) - Setup and program the "IoT Device" 25 | * [Module 3](module3) - Develop "Formatter" module 26 | * [Module 4](module4) - Azure Stream Analytics Edge job 27 | * [Module 5](module5) - Develop "Alert" module 28 | 29 | If you have questions or issues for the lab, check out our [troubleshooting](troubleshooting.md) guide! 30 | 31 | Below is a conceptual flow for the labs to help visualize what is taking place and how the data is flowing through the system ("T/H" is short for "temperature and humidity) 32 | 33 | ![conceptual drawing](/images/IoT-Edge-Labs-Conceptual-Design.png) 34 | 35 | ## Hardware 36 | 37 | For this lab, for simplicity of setup, we are using our Windows 10 desktops (running Docker and Linux containers) as the Edge device. For the Arduino device, we leverage an Arduino Uno (you can feel free to use any device that can send data over serial). For the labs we deliver directly to customers, we leverge the following kits: 38 | * Arduino Uno R3 “kit”: [kit](https://www.adafruit.com/product/193) ~$35 39 | * DHT22 temp/humidity sensor: [kit](https://www.adafruit.com/product/385) ~10 40 | 41 | ## Prerequisites 42 | 43 | >Note: For the lab exercises, we need an IoT Hub created in an Azure Subscription for which you have administrative access. 44 | 45 | In order to execute the hands-on labs, there are a number of pre-requisites that need to be installed and configured. Unless otherwise noted, the default installation of the items below are fine 46 | 47 | >Note: For in-person deliveries by the IoT GBBs, some of this may have been done for you. Please check with your instructor 48 | 49 | * Windows 10 Fall Creators Update (build 16299) 50 | * [Docker for Windows](https://docs.docker.com/docker-for-windows/install/) ** the "community edition" is fine. Make sure you install the STABLE version. A reboot may be required to enable Hyper-V 51 | 52 | >NOTE: because of some issues with Window containers, the labs are intended to be run with Linux containers (on a Windows host). Please ensure that you are running Linux containers. The best way to tell is to right-click on the "whale" in your notification bar and make sure you see "Switch to Windows containers" in the context menu. That shows that you are currently running Linux containers. If not, please make the switch. 53 | 54 | * [Visual Studio Code](https://code.visualstudio.com/) 55 | * [.NET Core SDK](https://www.microsoft.com/net/core#windowscmd) 56 | * [Arduino IDE](http://www.arduino.cc/) 57 | * [Open SSL](https://sourceforge.net/projects/openssl/) 58 | * for the lab instructions later, create a c:\utils folder and unzip the downloaded OpenSSL zip to c:\utils\ 59 | (so you should a folder structure that looks like this-> c:\utils\OpenSSL) 60 | * [git](https://git-scm.com/downloads/) ** installation of the default components and default configurations are fine 61 | 62 | * [Python 2.7 for Windows](https://www.python.org/downloads/) -- __**make sure it's 2.7.x, NOT 3.x.x**__ 63 | * during setup, elect to "add python 2.7 folder to the path" (see screenshot below -- You will need to SCROLL DOWN to see it) 64 | 65 | ![python_install](/images/python_install.png) 66 | -------------------------------------------------------------------------------- /module2/dotnet/readserial_nodevice/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO.Ports; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Microsoft.Azure.Devices.Client; 6 | using Microsoft.Azure.Devices.Client.Transport.Mqtt; 7 | using Microsoft.Azure.Devices.Shared; 8 | 9 | namespace readserial_nodevice 10 | { 11 | class Program 12 | { 13 | static string ConnectionString = ""; //don't forget the ;GatewayHostName=mygateway.local 14 | static bool _continue; 15 | static DeviceClient _deviceClient; 16 | 17 | static int counter = 0; 18 | const int timeBetweenMessages = 3000; 19 | 20 | //set min and maxes for temperature and humidity 21 | static double minTemp = 70.0; 22 | static double maxTemp = 90.0; 23 | static double minHumidity = 50.0; 24 | static double maxHumidity = 60.0; 25 | static int numSamples = 30; 26 | 27 | // reference variables 28 | static bool tempGoingUp = true; 29 | static bool humidityGoingUp = true; 30 | static double lastTemp = minTemp; 31 | static double lastHumidity = minHumidity; 32 | 33 | static double tempRange = (maxTemp - minTemp) / numSamples; 34 | static double humidityRange = (maxHumidity - minHumidity) / numSamples; 35 | 36 | static void Main(string[] args) 37 | { 38 | Thread readThread = new Thread(Read); 39 | 40 | InitDeviceClient().Wait(); 41 | 42 | _continue = true; 43 | readThread.Start(); 44 | 45 | Console.WriteLine("press to exit"); 46 | Console.ReadLine(); 47 | 48 | _continue = false; 49 | 50 | readThread.Join(); 51 | 52 | } 53 | 54 | static Task HandleDirectMethod(MethodRequest methodRequest, object userContext) 55 | { 56 | Console.WriteLine($"Direct Method ({methodRequest.Name}) invoked... "); 57 | Console.WriteLine("Returning response for method {0}", methodRequest.Name); 58 | 59 | string result = "'DM call successful'"; 60 | return Task.FromResult(new MethodResponse(System.Text.Encoding.UTF8.GetBytes(result), 200)); 61 | } 62 | 63 | static public async Task InitDeviceClient() 64 | { 65 | MqttTransportSettings mqttSetting = new MqttTransportSettings(TransportType.Mqtt_Tcp_Only); 66 | // During dev you might want to bypass the cert verification. It is highly recommended to verify certs systematically in production 67 | mqttSetting.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; 68 | ITransportSettings[] settings = { mqttSetting }; 69 | 70 | _deviceClient = DeviceClient.CreateFromConnectionString(ConnectionString, settings); 71 | await _deviceClient.OpenAsync(); 72 | Console.WriteLine($"Connected to IoT Edge with connection string [{ConnectionString}]"); 73 | 74 | _deviceClient.SetMethodHandlerAsync("ON", HandleDirectMethod, null).Wait(); 75 | _deviceClient.SetMethodHandlerAsync("OFF", HandleDirectMethod, null).Wait(); 76 | 77 | } 78 | 79 | public static void Read() 80 | { 81 | while (_continue) 82 | { 83 | try 84 | { 85 | double temp = 0.0; 86 | double humidity = 0.0; 87 | 88 | if(tempGoingUp) 89 | { 90 | temp = lastTemp + tempRange; 91 | if(temp > maxTemp) 92 | { 93 | temp = maxTemp; 94 | tempGoingUp = false; 95 | } 96 | } 97 | else 98 | { 99 | temp = lastTemp - tempRange; 100 | if(temp < minTemp) 101 | { 102 | temp = minTemp; 103 | tempGoingUp = true; 104 | } 105 | } 106 | 107 | lastTemp = temp; 108 | 109 | if(humidityGoingUp) 110 | { 111 | humidity = lastHumidity + humidityRange; 112 | if(humidity > maxHumidity) 113 | { 114 | humidity = maxHumidity; 115 | humidityGoingUp = false; 116 | } 117 | } 118 | else 119 | { 120 | humidity = lastHumidity - humidityRange; 121 | if(humidity < minHumidity) 122 | { 123 | humidity = minHumidity; 124 | humidityGoingUp = true; 125 | } 126 | } 127 | 128 | lastHumidity = humidity; 129 | 130 | string message = String.Format("{0:0.00},{1:0.00}", humidity, temp); 131 | 132 | var mess = new Message(System.Text.Encoding.ASCII.GetBytes(message)); 133 | 134 | Task t = _deviceClient.SendEventAsync(mess); 135 | Console.WriteLine($"Message sent({counter++}) {message}"); 136 | } 137 | catch (TimeoutException) { } 138 | 139 | Thread.Sleep(timeBetweenMessages); 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Azure IoT Edge Hands On Labs 2 | 3 | Created and maintained by the Microsoft Azure IoT Global Black Belts 4 | 5 | 6 | ## Troubleshooting 7 | 8 | This troubleshooting guide contains some tips for troubleshooting your labs. As a reminder, Azure IoT Edge is in *preview*, so you should not be shocked to find that there are bugs, idiosyncracies, and stuff that just doesn't work. With that said, the product is generally in very good shape and is of very high quality for a preview. 9 | 10 | ### General tips 11 | 12 | Read the instructions VERY carefully. A good number of the 'issues' found in early internal testing existed between the seat and the keyboard :-). The instructions can get very detailed in places, so if something doesn't work, make sure to re-read the instructions. 13 | 14 | Make sure you are always working with the latest set of instructions (i.e. refresh your browser). We find and fix stuff regularly. 15 | 16 | ### Docker tips 17 | 18 | For these labs, at least for now, we are using Docker for Windows with *Linux* containers. There is no reason to believe they won't work with Windows containers, but we haven't tested them. If you have issues, make sure Docker is running Linux containers (right click on the 'whale' in your notification bar and see if "switch to Windows containers..." is there. If so, that means you are using Linux containers) 19 | 20 | _*A few very useful docker commands:*_ 21 | 22 | * docker ps: gives a list of running docker containers 23 | * docker images : gives a list of locally caches images 24 | * docker image rm -f \ : removes (forceably) a locally cached image (forcing a fresh re-download) where \ is the image name in the format of \/\:\. You can alternately just specify the image ID (found from 'docker images') instead of the name. Generally you want to make sure the Edge runtime is stopped when you do this (iotedgectl stop) 25 | * docker container ls -a : gives a list of docker containers (whether running or not) 26 | * docker container rm -f \ : removes (forceably) a docker container and makes the edge runtime recreate it when it next starts. Generally you want to make sure the Edge runtime is stopped when you do this (iotedgectl stop) 27 | * docker logs -f \ : shows (and follows) the logs for a running container. CTRL-C to exit it. 28 | 29 | Of all of these, 'docker logs -f \' is your best friend. It shows anything written to the console (i.e. printf, Console.Writeline, etc) from within the container. All of the MSFT provided modules, and the ones you develop in the lab, provide useful information in the logs 30 | 31 | _*Restarting/Resetting Docker:*_ 32 | 33 | Sometimes Docker can get in a weird state. We've seen this a few times when a machine sleeps or hibernates. One thing, short of a reboot, that you can do (after stopping Edge!) is to right click on the whale in your notification area, click 'settings", click on the 'reset' tab, and click "Restart Docker". If that doesn't work, "Reset to Factory Defaults" is another good option. The need for this doesn't happen often, but has happened. 34 | 35 | ### Lab troubleshooting tips 36 | 37 | _*General tips*_ 38 | 39 | * As mentioned above, make sure you are running Linux containers. Right click on the 'whale' in your notification area and make sure it says "Switch to Windows containers" (which means you are currently correctly running Linux containers) 40 | * check the case on everything! module names, routes, etc are all CASE SENSITIVE. If something is not connecting or data is not flowing, check the case between the module names and the routes. 41 | * if you aren't seeing data in the "D2C monitoring" in VS Code, make sure you are looking at the right device. For module2, you should be looking at your "IoT Leaf Device" (i.e. the one from the python script). For module 3 or subsequent modules, you should be monitoring your IoT *EDGE* device (because once we insert a module in between the device and IoT Hub, it becomes a different 'message' from a different source) 42 | * when it comes to troubleshooting, the first stop should be the docker logs for the modules. We can't say this enough :-) 43 | 44 | _*when I try to start IoT Edge (via iotedgectl start), I get an error mentioning the "Docker API"*_ 45 | 46 | This can happen for a few reasons: 47 | * you are running Windows containers instead of Linux containers. To check, right-click on the docker "whale" down in your notification area. If it says "switch to Windows containers", then you are currently running Linux containers and are ok. If it says "switch to Linux containers", please do so and then try again! 48 | * some networking change has happened (different wifi, etc) since docker started. Restart docker by right clicking on the docker "whale" in the notification area, choose "settings", go the the 'reset' tab, and click "restart docker" 49 | * you aren't *supposed* to need to run in an adminitrative command prompt, but it doesn't hurt to try :-) 50 | 51 | _*when I try to install the edge runtime control script with 'pip install -U azure-iot-edge-runtime-control', it tells me pip is not found*_ 52 | 53 | Make sure that c:\python27\scripts is in your path. If not, add it and re-open your command prompt 54 | 55 | _*when my IoT Device (python script) tries to connect to Edge, I get a TLS error or some other error*_ 56 | 57 | * make sure you are running the pre-release version of the Python SDK. If you run "pip list", you should see an entry for "azure-iothub-device-client (1.2.0.0b0)" 58 | * Make sure that your GatewayHostName parameter is spelled correctly ('mygateway.local') 59 | * make sure you can 'ping' the hostname (should resolve to 127.0.0.1) 60 | * make sure that the edge runtime was started with the right certs. Open c:\programdata\azure-iot-edge\config\config.json and make sure the "certificates" section matches this: 61 | ![edgecerts](/images/edgecerts.png) 62 | * make sure that the edgeHub is actually running and listening on port 8883. run 'docker ps' to confirm (as in the image) 63 | ![edgeHubrunning](/images/edgeHubrunning.png) 64 | * finally, look in the edgeHub logs (docker logs -f edgeHub) for any errors 65 | 66 | _*My module(s) are up and running fine (via docker ps and docker logs), but no messages are 'flowing' through them. In other words, messages are going into edgeHub from my python script, but don't seem to get routed anywhere (including IoT Hub)*_ 67 | 68 | We've seen a few times where edgeHub seems to just kind-of get 'stuck'. No errors in the log, and you can send data, C2D messages, DM calls, etc through it, but no messages get routed to either modules or IoT Hub. The only fix we've found so far is to delete, and let Edge re-create, the edgeHub container. 69 | 70 | To do so: 71 | * stop your python script/IoT device if it is running 72 | * stop IoT Edge (iotedgectl stop) 73 | * delete the edgeHub container 74 | * docker container rm -f edgeHub 75 | * delete the edgeHub image (probably not necessary, but why not) 76 | * docker image rm -f microsoft/azureiotedge-hub:1.0-preview 77 | * restart IoT Edge (iotedgectl start) 78 | * restart your IoT device 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /module4/README.MD: -------------------------------------------------------------------------------- 1 | # Azure IoT Edge Hands On Labs - Module 4 2 | 3 | Created and maintained by the Microsoft Azure IoT Global Black Belts 4 | 5 | ## Introduction 6 | 7 | For this step of the lab, we are going to create an Azure Stream Analytics job that will run on our IoT Edge device. Azure Stream Analytics (ASA) is our SQL-based near real time analytics engine. One of the great value propositions of running ASA on the Edge is that you can create and manage the ASA query in the cloud, and have it pushed to be executed on the Edge. 8 | 9 | For our use case, we are going to have the ASA job do two things concurrently: 10 | 11 | * aggregate the temperature and humidity data, which comes in at a higher rate, to a lower frequency of every 20 seconds 12 | * look for cases in which the temperature transitions above or below 80 degrees. This will kick off an 'alert' message that we can react to downstream of the ASA job 13 | 14 | ## Creating the ASA job 15 | 16 | Our ASA job will be set up to take the messages produced by our formatter module in module 3 of the labs. 17 | 18 | An ASA job consists of three parts: 19 | * one or more "inputs", or sources of either streaming or reference data 20 | * one or more "outputs" or sinks for the query results 21 | * the "query" that represents the processing of the job, which takes data from the inputs, processes it, and writes the results to one or more outputs 22 | 23 | To create the ASA job: 24 | 25 | * in the Azure portal, navigate in the left nav bar to the Azure Stream Analytics jobs blade and click Add 26 | * give your ASA job a unique name (e.g. edgeASAJob) 27 | * under resource group, choose "use existing" and pick the same resource group that contains your IoT Hub 28 | * for Hosting Environment, choose "Edge" (see NOTE below) 29 | * click "Create" 30 | 31 | NOTE: there is a bug in the Azure portal that may be fixed by the time you do these labs, however, if you do not see the "Hosting Environment" choice in the UI, use [this link](https://portal.azure.com/?Microsoft_Azure_StreamAnalytics_onedge=true) to access the Azure Portal instead 32 | 33 | After a few moments, your ASA job will be created. Click "Go to Resource" to navigate to the portal blade for your job 34 | 35 | * click on the "inputs" box and click "Add stream input", and click "Edge Hub" 36 | * give your input the name "inputFromHub" and leave the other settings as default. 37 | * click Create to create your input 38 | 39 | Navigate back to the blade for your ASA job and click on the "outputs" box to add outputs 40 | 41 | * Our job is going to leverage two different outputs, one for the aggregated temperature data and one for the alerts 42 | * click Add to create a new output and choose "Edge Hub" 43 | * name your output asaAggregatedTemp for the aggregated temperature data 44 | * leave the remaining settings at default and click "Create" 45 | * repeat the above three steps for the alert output (name it asaAlertTemp) 46 | 47 | The next step is to specify the query. In the upper right of the query window, click on the "Edit query" to open the query editor. Copy/paste in this query: 48 | 49 | ```SQL 50 | -- get aggregated temp/humidity every XX seconds 51 | SELECT 52 | deviceID, 53 | AVG(temperature) as AvgTemp, 54 | AVG(humidity) as AvgHumidity, 55 | System.Timestamp as eventdatetime 56 | INTO asaAggregatedTemp 57 | FROM inputFromHub 58 | WHERE temperature IS NOT NULL 59 | GROUP BY 60 | deviceID, 61 | TumblingWindow(s, 30) 62 | 63 | -- determine if we are making a 'transition' above or below 80 degress 64 | SELECT * 65 | INTO asaAlertTemp 66 | FROM 67 | ( 68 | SELECT 69 | deviceID, 70 | temperature, 71 | CASE 72 | WHEN CAST(temperature as bigint) >= 80 THEN 'HIGH' 73 | ELSE 'LOW' 74 | END as tempState, 75 | System.Timestamp as eventdatetime 76 | FROM inputFromHub 77 | WHERE 78 | temperature IS NOT NULL 79 | ) x 80 | WHERE 81 | LAG(tempState, 1) OVER (PARTITION BY deviceID LIMIT DURATION(minute, 10)) <> tempState 82 | 83 | ``` 84 | 85 | If we break down the query above, it really has two main parts: 86 | 87 | * the first query takes the AVG of humidity and temp over a tumbling (aka back-to-back) window of 30 seconds and sends this output to the aggregated temperature data output 88 | * the second query uses the SQL LAG function to look at, and compare the "current" TempState (i.e HIGH or LOW) and the TempState of the previous row. That's what LAG does. If the values are different, then we have either transitioned from LOW to HIGH, or HIGH to LOW, so we generate an Alert message to our alert output 89 | 90 | * Click Save to save your query and close the editor 91 | 92 | ## Deploy the ASA job 93 | 94 | In order to deploy our ASA job to Edge, the first step we need to do is to create a storage account in Azure. The storage account is used to hold the details of the job and as a place from which the ASA on Edge module can download it. 95 | 96 | To create a storage account: 97 | 98 | * in the Azure portal, navigate to "Storage accounts" on the left-hand nav and click "Add" 99 | * give the account a name (which has to be globally unique) 100 | * for resource group, use the same one we used for the ASA job and IoT Hub 101 | * leave all the other settings at default and click "Create" 102 | * after the account gets created, navigate to it and click "Browse Blobs" 103 | * Create a new container (give it a name) and for access, choose "Container" level and select "Ok" 104 | 105 | 106 | Now we are ready to deploy our ASA job to our Edge device. 107 | 108 | * navigate back to your IoT Hub and then to your Edge device 109 | * click "Set Modules" 110 | * select "Import Azure Stream Analytics IoT Edge Module" 111 | * select your subscription, and the ASA job you created earlier 112 | * under Storage account, select your subscription and the storage account you created earlier 113 | * click Save 114 | 115 | > NOTE: There is a temporary certificate validation issue with IoT Edge. As such, the default ASA module is broken. We have a temporary work around using a specially built-version of the ASA module. To leverage this module, before continuing, follow the steps documented [here](ASAWorkaround.md). 116 | 117 | 118 | * click "next" to configure our routes 119 | * on the 'specify routes' screen, enter the following routes 120 | 121 | ```json 122 | { 123 | "routes": { 124 | "toFormatterFromDevices": "FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO BrokeredEndpoint(\"/modules/formattermodule/inputs/input1\")", 125 | "toASAJob": "FROM /messages/modules/formattermodule/outputs/output1 INTO BrokeredEndpoint(\"/modules/edgeASAJob/inputs/inputFromHub\")", 126 | "asaAlertsToIoTHub": "FROM /messages/modules/edgeASAJob/outputs/asaAlertTemp INTO $upstream", 127 | "asaAggrToIoTHub": "FROM /messages/modules/edgeASAJob/outputs/asaAggregatedTemp INTO $upstream" 128 | } 129 | } 130 | ``` 131 | 132 | * replace "edgeASAJob" above with the name of your ASA module if you used a different name. Ditto for "formatttermodule" 133 | 134 | click 'next' and 'finish' to publish our routes. 135 | 136 | ## Test our module 137 | 138 | re-start the python script (or .NET Core app) that represents our device. Use "docker ps" and "docker logs -f \" to see the various debug messages from the modules 139 | 140 | If it is not still running, restart the D2C message monitoring within VS Code. You should see the aggregated temperature data come through every 30 seconds or so. If you hold your finger on the temperature sensor on the Arduinio device enough to make it go above (and then release and let it fall below) 80 degrees, you should also see the Alert messages come through to IoT Hub. 141 | 142 | ## Summary 143 | 144 | So now we have ASA generating aggregated temperature/humidity data at a lower and less costly message rate to the cloud, and also doing local processing to generate temperture 'alerts'. However, we are not yet taking action on those alerts. We will do that in the next module (module 5). 145 | 146 | To continue with module 5, click [here](/module5) -------------------------------------------------------------------------------- /module2/SourceModule/Program.cs: -------------------------------------------------------------------------------- 1 | namespace TempModule 2 | { 3 | using System; 4 | using System.IO; 5 | using System.Collections.Generic; 6 | using System.Runtime.InteropServices; 7 | using System.Runtime.Loader; 8 | using System.Security.Cryptography.X509Certificates; 9 | using System.Text; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | using Microsoft.Azure.Devices.Client; 13 | using Microsoft.Azure.Devices.Client.Transport.Mqtt; 14 | using Microsoft.Azure.Devices.Shared; 15 | using Newtonsoft.Json; 16 | 17 | class Program 18 | { 19 | static int counter = 0; 20 | static DeviceClient ioTHubModuleClient = null; 21 | // static Random rnd = new Random(); 22 | const int timeBetweenMessages = 3000; 23 | 24 | //set min and maxes for temperature and humidity 25 | static double minTemp = 70.0; 26 | static double maxTemp = 90.0; 27 | static double minHumidity = 50.0; 28 | static double maxHumidity = 60.0; 29 | static int numSamples = 30; 30 | 31 | // reference variables 32 | static bool tempGoingUp = true; 33 | static bool humidityGoingUp = true; 34 | static double lastTemp = minTemp; 35 | static double lastHumidity = minHumidity; 36 | 37 | static double tempRange = (maxTemp - minTemp) / numSamples; 38 | static double humidityRange = (maxHumidity - minHumidity) / numSamples; 39 | 40 | static void Main(string[] args) 41 | { 42 | // The Edge runtime gives us the connection string we need -- it is injected as an environment variable 43 | string connectionString = Environment.GetEnvironmentVariable("EdgeHubConnectionString"); 44 | 45 | // Cert verification is not yet fully functional when using Windows OS for the container 46 | bool bypassCertVerification = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); 47 | if (!bypassCertVerification) InstallCert(); 48 | Init(connectionString, bypassCertVerification).Wait(); 49 | 50 | System.Timers.Timer t = new System.Timers.Timer(timeBetweenMessages); 51 | t.Elapsed += OnTimerEvent; 52 | t.AutoReset = true; 53 | t.Start(); 54 | 55 | // Wait until the app unloads or is cancelled 56 | var cts = new CancellationTokenSource(); 57 | AssemblyLoadContext.Default.Unloading += (ctx) => cts.Cancel(); 58 | Console.CancelKeyPress += (sender, cpe) => cts.Cancel(); 59 | WhenCancelled(cts.Token).Wait(); 60 | } 61 | 62 | /// 63 | /// Handles cleanup operations when app is cancelled or unloads 64 | /// 65 | public static Task WhenCancelled(CancellationToken cancellationToken) 66 | { 67 | var tcs = new TaskCompletionSource(); 68 | cancellationToken.Register(s => ((TaskCompletionSource)s).SetResult(true), tcs); 69 | return tcs.Task; 70 | } 71 | 72 | /// 73 | /// Add certificate in local cert store for use by client for secure connection to IoT Edge runtime 74 | /// 75 | static void InstallCert() 76 | { 77 | string certPath = Environment.GetEnvironmentVariable("EdgeModuleCACertificateFile"); 78 | if (string.IsNullOrWhiteSpace(certPath)) 79 | { 80 | // We cannot proceed further without a proper cert file 81 | Console.WriteLine($"Missing path to certificate collection file: {certPath}"); 82 | throw new InvalidOperationException("Missing path to certificate file."); 83 | } 84 | else if (!File.Exists(certPath)) 85 | { 86 | // We cannot proceed further without a proper cert file 87 | Console.WriteLine($"Missing path to certificate collection file: {certPath}"); 88 | throw new InvalidOperationException("Missing certificate file."); 89 | } 90 | X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser); 91 | store.Open(OpenFlags.ReadWrite); 92 | store.Add(new X509Certificate2(X509Certificate2.CreateFromCertFile(certPath))); 93 | Console.WriteLine("Added Cert: " + certPath); 94 | store.Close(); 95 | } 96 | 97 | /// 98 | /// Initializes the DeviceClient and sets up the callback to receive 99 | /// messages containing temperature information 100 | /// 101 | static async Task Init(string connectionString, bool bypassCertVerification = false) 102 | { 103 | Console.WriteLine("Connection String {0}", connectionString); 104 | 105 | MqttTransportSettings mqttSetting = new MqttTransportSettings(TransportType.Mqtt_Tcp_Only); 106 | // During dev you might want to bypass the cert verification. It is highly recommended to verify certs systematically in production 107 | if (bypassCertVerification) 108 | { 109 | mqttSetting.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; 110 | } 111 | ITransportSettings[] settings = { mqttSetting }; 112 | 113 | // Open a connection to the Edge runtime 114 | // DeviceClient ioTHubModuleClient = DeviceClient.CreateFromConnectionString(connectionString, settings); 115 | ioTHubModuleClient = DeviceClient.CreateFromConnectionString(connectionString, settings); 116 | await ioTHubModuleClient.OpenAsync(); 117 | Console.WriteLine("IoT Hub module client initialized."); 118 | 119 | // Register callback to be called when a message is received by the module 120 | // await ioTHubModuleClient.SetInputMessageHandlerAsync("input1", PipeMessage, ioTHubModuleClient); 121 | } 122 | 123 | static async void OnTimerEvent(object source, System.Timers.ElapsedEventArgs e) 124 | { 125 | 126 | //Console.WriteLine("Timer expired"); 127 | 128 | // double temp = (rnd.NextDouble() * (90-50)) + 50; 129 | // double humidity = (rnd.NextDouble() * (70-40)) + 40; 130 | double temp = 0.0; 131 | double humidity = 0.0; 132 | 133 | if(tempGoingUp) 134 | { 135 | temp = lastTemp + tempRange; 136 | if(temp > maxTemp) 137 | { 138 | temp = maxTemp; 139 | tempGoingUp = false; 140 | } 141 | } 142 | else 143 | { 144 | temp = lastTemp - tempRange; 145 | if(temp < minTemp) 146 | { 147 | temp = minTemp; 148 | tempGoingUp = true; 149 | } 150 | } 151 | 152 | lastTemp = temp; 153 | 154 | if(humidityGoingUp) 155 | { 156 | humidity = lastHumidity + humidityRange; 157 | if(humidity > maxHumidity) 158 | { 159 | humidity = maxHumidity; 160 | humidityGoingUp = false; 161 | } 162 | } 163 | else 164 | { 165 | humidity = lastHumidity - humidityRange; 166 | if(humidity < minHumidity) 167 | { 168 | humidity = minHumidity; 169 | humidityGoingUp = true; 170 | } 171 | } 172 | 173 | lastHumidity = humidity; 174 | 175 | string sMessage = String.Format("{0:0.00},{1:0.00}", humidity, temp); 176 | 177 | var mess = new Message(Encoding.ASCII.GetBytes(sMessage)); 178 | 179 | Console.WriteLine($"Message sent({counter++}) {sMessage}"); 180 | 181 | await ioTHubModuleClient.SendEventAsync("output1", mess); 182 | 183 | } 184 | } 185 | } 186 | 187 | 188 | -------------------------------------------------------------------------------- /module1/README.md: -------------------------------------------------------------------------------- 1 | # Azure IoT Edge Hands On Labs - Module 1 2 | 3 | Created and maintained by the Microsoft Azure IoT Global Black Belts 4 | 5 | ## Azure Portal Access 6 | 7 | Because the Azure Streaming Analytics on Edge feature is in preview, to access the Azure Portal, use this specially formatted URL throughout the labs: 8 | 9 | https://portal.azure.com/?Microsoft_Azure_StreamAnalytics_onedge=true 10 | 11 | ## Create an IoT Hub and an "Edge Device" 12 | 13 | 14 | You can create an IoT hub using the following methods: 15 | 16 | * The + New option opens the blade shown in the following screen shot. The steps for creating the IoT hub through this method and through the marketplace are identical. 17 | 18 | * In the Marketplace, choose Create to open the blade shown in the following screen shot. 19 | 20 | * Provide a name and a resource group. You can use a free tier but only one free tier is available per subscription. 21 | 22 | ![Create IoT Hub](/images/create-iothub.png) 23 | 24 | While you are in the Azure portal, let's go ahead and grab a couple of important connection parameters and create an IoT Edge Device 25 | 26 | In the IoT Hub blade of the Azure portal for your created IoT Hub, do the following: 27 | * In the left-hand nav bar, click on "Shared Access Policies" and then click on "iothubowner", copy the "Connection String - Primary Key" string and paste it into Notepad. We'll need it later. This is your "IoTHub Owner Connection string" (keep that in mind, or make a note next to it in Notepad, we will use it in subsequent labs). 28 | * Close the "Shared Access Policy" blade 29 | 30 | Now let's create the "edge device" 31 | * In the left-hand nav bar, click on "IoT Edge (preview)" 32 | * click "Add Edge Device" 33 | * Give your IoT Edge Device a name and click "Create" 34 | * once created, find the IoT Edge Device connection string (primary key) and copy/paste this into Notepad. This is the "IoT Edge Device" connection string 35 | 36 | ## Create docker hub account 37 | 38 | IoT Edge modules are pulled by the Edge runtime from a docker containder image repository. You can host one locally in your own network/infrastructure if you choose, Azure offers a [container service](https://azure.microsoft.com/en-us/services/container-service/) and of course, Docker themselves offer a repository (docker hub). For simplicity, we will run the labs based off of hosting images in docker hub. If you feel confident in doing so, feel free to leverage other docker image respositories instead of docker hub if you wish. 39 | 40 | For Docker Hub, you need a Docker ID. Create one by visting www.docker.com and clicking on "Create Docker ID" and following the instructions. Remember the docker ID you create, as we'll use it later. If you are given a choice during sign up, choose a repository visibility of 'public'. Generally, docker images are referred to in a three part name: \/image:tag where "respository" (if using Docker Hub) is just your Docker ID, image is your image name, and tag is an optional "tag" you can use to have multiple images with the same name (often used for versioning). 41 | 42 | ## Clone the lab materials locally 43 | 44 | The first step is to clone the lab materials locally (you'll need a few components of module2 locally to run). 45 | 46 | ```cmd 47 | cd \ 48 | git clone https://github.com/azureiotgbb/azure-iot-edge-hol 49 | ``` 50 | 51 | ## Additional setup 52 | 53 | There are a few final steps needed to set up our specific lab scenario. We are using our Edge device "as a gateway*, so we need: 54 | 55 | 1. Our IoT Device to be able to find it 56 | 2. Have valid certificates so the IoT Device will open a successful TLS connection to the Edge 57 | 58 | First let's add a host file entry for our Edge device. This will let our "IoT Device" resolve and find our Edge gateway. 59 | 60 | * Open a command prompt __*as an Administrator*__ 61 | * Type the command bellow to open the hosts file in notepad 62 | ``` 63 | notepad.exe c:\windows\system32\drivers\etc\hosts 64 | ``` 65 | * Add a row at the bottom with the following and then save and close the file 66 | ``` 67 | 127.0.0.1 mygateway.local 68 | ``` 69 | * Confirm you can successfully "ping mygateway.local" 70 | 71 | Now let's create the certificates needed 72 | 73 | * Open a PowerShell session __*as an Adminstrator*__ 74 | 75 | >Note: Do this in a plain Powershell window. It does not work in the PowerShell ISE for some reason. 76 | 77 | First, we will clone the Azure IoT C sdk. We need this to get the certificate generation scripts. Also, while Edge is in public preview, we need the 'modules-preview' branch of the SDK. 78 | 79 | After cloning the C sdk, we prepare the PowerShell environment to we can generate the certificates. 80 | 81 | Run the following commands from the root of the **"C" drive** 82 | 83 | cd \ 84 | 85 | git clone -b modules-preview http://github.com/azure/azure-iot-sdk-c 86 | 87 | > Note - there is a temporary bug in the script that we will use to generate our TLS certificates for IoT Edge. To work around it, perform the following steps 88 | 89 | in notepad, open \azure-iot-sdk-c\tools\CACertificates\ca-certs.ps1 90 | search down until you find the line: 91 | "function New-CACertsEdgeDevice([string]$deviceName, [string]$signingCertSubject=($_intermediateCertSubject -f "1"))" 92 | and replace it with the following (without the quotes) 93 | "function New-CACertsEdgeDevice([string]$deviceName, [string]$signingCertSubject=("CN=$_intermediateCertCommonName" -f "1"))" 94 | save the ca-certs.ps1 file and close 95 | 96 | Now we are ready to generate our TLS certificates for IoT Edge 97 | 98 | mkdir c:\edge 99 | cd \edge 100 | Set-ExecutionPolicy Unrestricted 101 | $ENV:PATH += ";c:\utils\OpenSSL\bin" 102 | $ENV:OPENSSL_CONF="c:\utils\OpenSSL\bin\openssl.cnf" 103 | . \azure-iot-sdk-c\tools\CACertificates\ca-certs.ps1 104 | Test-CACertsPrerequisites 105 | 106 | Make sure it returns the result "SUCCESS". If the Test-CACertsprequisites call fails, it means that the local machine already contains Azure IoT test certs (possibly from a previously deployment). If that happens, you need to follow Step 5 - Cleanup of the instructions [here](https://github.com/Azure/azure-iot-sdk-c/blob/modules-preview/tools/CACertificates/CACertificateOverview.md) before moving on 107 | 108 | >Note: Do not close the powershell session yet. If you do, just reopen it and re run lines 4-6 109 | 110 | We are now ready to generate the TLS certificates for our Edge device. Make sure you are still in the __c:\edge folder__ in your PowerShell session and run the command bellow to generate our test certificates. In production, you would use a real CA. 111 | 112 | New-CACertsCertChain rsa 113 | 114 | In the azure portal, navigate back to your IoT Hub and click on "Certificates" on the left-nav and click "+Add". Give your certificate a name, and upload the c:\edge\RootCA.cer" file 115 | 116 | Now we need to generate certs for our specific gateway. In Powershell run: 117 | 118 | New-CACertsEdgeDevice myGateway 119 | 120 | 121 | This will generate the gateway specific certificates (MyGateway.*). When prompted to enter a password during the signing process, just enter "1234". 122 | 123 | >Note: If anything goes wrong during this process and you need to repeat it, you'll likely need to clean up the existing certs before generating new ones. To do so, follow Step 5 - Cleanup, of the process outlined [here](https://github.com/Azure/azure-iot-sdk-c/blob/modules-preview/tools/CACertificates/CACertificateOverview.md) 124 | 125 | ## Install IoT Edge configuration tool 126 | 127 | Microsoft provides a python-based, cross-platform configuration and setup tool for IoT Edge. To install the tool, open an administrator command prompt and run: 128 | 129 | ```cmd 130 | pip install -U azure-iot-edge-runtime-ctl 131 | ``` 132 | 133 | ## Configure and start IoT Edge 134 | 135 | Now that we have all the pieces in place, we are ready to start up our IoT Edge device. We will start it by specifying the IoT Edge Device connection string capture above, as well as specifying the certificates we generated to allow downstream devices to establish valid TLS sessions with our Edge gateway. 136 | 137 | To setup and configure our IoT Edge device, make sure Docker is running and run the following command: (if you used '1234' for the password above, enter it again here when prompted). 138 | 139 | ``` 140 | 141 | iotedgectl setup --connection-string "" --edge-hostname "mygateway.local" --device-ca-cert-file c:\edge\myGateway-public.pem --device-ca-chain-cert-file c:\edge\myGateway-all.pem --device-ca-private-key-file c:\edge\myGateway-private.pem --owner-ca-cert-file c:\edge\RootCA.pem 142 | 143 | ``` 144 | Replace *IoT Edge Device connection string* with the Edge device connection string you captured above. If it prompts you for a password for the edge private cert, use '12345' (NOTE: different from the password above!) 145 | 146 | We're ready now to start our IoT Edge device 147 | 148 | ``` 149 | iotedgectl start 150 | ``` 151 | 152 | You can see the status of the docker images by running 153 | 154 | ``` 155 | docker ps 156 | ``` 157 | 158 | At this point, because we haven't added any modules to our Edge device yet, you should only see one container/module running called 'edgeAgent' 159 | 160 | If you want to see if the edge Agent successfully started, run 161 | 162 | ``` 163 | docker logs -f edgeAgent 164 | ``` 165 | 166 | >Note: You may see an error in the edgeAgent logs about having an 'empty configuration'. That's fine because we haven't set a configuration yet! 167 | 168 | CTRL-C to exit the logs when you are ready 169 | 170 | __**Congratulations -- You now have an IoT Edge device up and running and ready to use**__ 171 | 172 | To continue with module 2, click [here](/module2) 173 | -------------------------------------------------------------------------------- /module5/README.MD: -------------------------------------------------------------------------------- 1 | # Azure IoT Edge Hands On Labs - Module 5 2 | 3 | Created and maintained by the Microsoft Azure IoT Global Black Belts 4 | 5 | ## Introduction 6 | 7 | For this step of the lab, we are going to create an IoT Edge module that will respond to the "High Temperature Alert" message generated from our Azure Stream Analytics on the Edge module in module 4. This module will take that alert, and send a Direct Method call to our device to tell it to turn on or off a "high temperature" alert LED. This is a simple example, but demonstrates communicating back to a device from a module. More importantly, along with module 4, it shows an example of how to take local "action" on the Edge in situations where you need low latency processing and action on the edge. 8 | 9 | We will develop our module in C# using .NET Core. .NET Core is the cross-platform version of Microsoft's .NET framework. The module and image we develop in this section can be used, unchanged, on x86/x64 based Linux distributions, and can be cross compiled for ARM distributions as well. 10 | 11 | We are primarily using C# and .NET Core for this lab because it is the most completely 'ready' language in terms of tooling at the time the labs are being written (during public preview). However, by General Availability time for IoT Edge, you will be able to develop IoT Edge modules in any supported Azure IoT language, including C, C#, Java, Node, and Python. 12 | 13 | ## Developing our module 14 | 15 | ### Creating the module "skeleton" 16 | 17 | We will use VS Code to develop our module. This process will be very similar to the actions taken in Module 3 18 | 19 | * in VS Code, click on File -> Open Folder and navigate to the c:\edge folder we created before 20 | * hit CTRL and + to open the Integrated Terminal window in VS Code. 21 | * We will create the "scaffolding" for our IoT Edge module using the IoT Edge module template provided by the IoT Edge product team and previously installed in module 3. In the integrated terminal, run the following command 22 | 23 | ```cmd 24 | dotnet new aziotedgemodule -n AlertModule -r /alertmodule 25 | ``` 26 | 27 | ### Modify the sample implementation 28 | 29 | Now lets modify the sample code to implement our Alert module. 30 | 31 | * in addition to the "Device Client" that other modules use, the Alerts sample also needs to use the "Service Client" to send Direct Method calls. To add the service client, open up the alertModule.csproj file in VS Code and add the following line in the \ section of the file and save the changes. 32 | 33 | In the Integrated Terminal Window, to add the new package reference (to the AlertModule.csproj file) and install it, type 34 | 35 | ```PowerShell 36 | cd AlertModule 37 | 38 | dotnet add package Microsoft.Azure.Devices --version 1.16.0-preview-003 39 | 40 | dotnet restore 41 | ``` 42 | 43 | * Open the Program.cs file, and in the "using" section above the Program class, add the two following 'using' statements 44 | 45 | ```CSharp 46 | using Newtonsoft.Json; 47 | using Microsoft.Azure.Devices; 48 | using Message = Microsoft.Azure.Devices.Client.Message; 49 | using TransportType = Microsoft.Azure.Devices.Client.TransportType; 50 | ``` 51 | 52 | * in Program.cs, above the "Program" class, add the C# class that will represent our message we want to publish to the Hub 53 | 54 | ```CSharp 55 | class Alert 56 | { 57 | public string deviceID { get; set; } 58 | public string tempState { get; set; } 59 | public float temperature { get; set; } 60 | public DateTime eventdatetime { get; set; } 61 | } 62 | ``` 63 | 64 | * at the top of the "Program" class (just below the line that reads "static int counter"), add the following code to declare an instance of the ServiceClient 65 | 66 | ```CSharp 67 | static ServiceClient iotServiceClient; 68 | ``` 69 | 70 | > Note: there is a temporary bug in the certificate validation code for IoT Edge. The below code change is necessary to work around that bug 71 | 72 | * Temporarily we will be bypassing certicate validation in our module. So do so, locate this line of code at the top of the "Main" function 73 | 74 | ```CSharp 75 | bool bypassCertVerification = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); 76 | ``` 77 | 78 | and replace it with 79 | 80 | ```CSharp 81 | bool bypassCertVerification = true; 82 | ``` 83 | 84 | * In the Init function, right below the call to DeviceClient.CreateFromConnectionString, add this call 85 | 86 | ```CSharp 87 | iotServiceClient = ServiceClient.CreateFromConnectionString(connectionString); 88 | ``` 89 | 90 | * the balance of our work will be in the PipeMessage function. the top part of the function, which gets the "Device Client" instance that is stored in Context and makes sure it's valid, and that opens the message and gets it's content as a string, is boiler-plate and is fine for our purposes. 91 | 92 | The rest of the work we will be doing is inside the "if" block below (which checks to make sure we don't have an empty message): 93 | 94 | ```CSharp 95 | if (!string.IsNullOrEmpty(messageString)) 96 | { 97 | } 98 | ``` 99 | 100 | * replace the code within the if block above, with the below code 101 | 102 | ```CSharp 103 | string command = ""; 104 | 105 | Console.WriteLine($"Received message, body: [{messageString}]"); 106 | 107 | var alertMsg = JsonConvert.DeserializeObject(messageString)[0]; 108 | 109 | if(alertMsg.tempState == "HIGH") 110 | command = "ON"; 111 | else 112 | command = "OFF"; 113 | 114 | Console.WriteLine($"Invoking Direct Method to {alertMsg.deviceID} for tempState={alertMsg.tempState}"); 115 | 116 | try { 117 | var result = await iotServiceClient.InvokeDeviceMethodAsync(alertMsg.deviceID, new CloudToDeviceMethod(command)); 118 | Console.WriteLine($"Result status: {result.Status}"); 119 | } 120 | catch(Exception e) 121 | { 122 | Console.WriteLine($"Exception caught while invoking DM: {e.ToString()}"); 123 | } 124 | ``` 125 | 126 | * the code above does the following things 127 | * Receives the "Alert" message passed to use from Stream Analytics on the Edge 128 | * parses the JSON message into an Alert object (technically, ASA passes us a JSON array of only one element, so we take the 'first' element) 129 | * pulls out the device ID of the device that caused the alert, and figures out, based on the 'tempstate' (HIGH or LOW) whether to send the "ON" or "OFF" command to the device 130 | * using the ServiceClient object, makes the Direct Method call. 131 | 132 | * save your changes to Program.cs 133 | 134 | ## Deploying our module 135 | 136 | Now that our module is created, we need to deploy it to our Edge device and get our messages routed through it. 137 | 138 | ### Log into Docker 139 | 140 | The first step is to log into Docker in the Terminal window. 141 | 142 | ```` 143 | docker login -u -p 144 | ```` 145 | 146 | ### Upload the image to Docker 147 | 148 | In VS Code explorer: 149 | 150 | * Right-click the module.json file and click "Build and Push IoT Edge module Docker Image". 151 | * In the pop-up dropdown box at the top of the VS Code window, select 'amd64' (Linux container). 152 | 153 | VS Code then builds your code, containerize the ````AlertModule.dll```` and push it to the container registry you specified. 154 | 155 | Our module is now in Docker with the tag ````0.0.1-amd64```` 156 | 157 | 158 | ## Deploy Edge module 159 | 160 | In this section, we will get the module created above deployed and view the results. 161 | 162 | * in the Azure portal, navigate to your IoT Hub, click on IoT Edge Devices (preview) on the left nav, click on your IoT Edge device 163 | * click on "Set Modules" in the top menu bar. 164 | * In the Set Modules blade, click on "Add IoT Edge Module" 165 | * In the "IoT Edge Modules" dialog, give your module a name (for example: AlertModule). Remember the name you used, including the proper 'case' of the letters, as we'll need that when we set the routes in the next step. 166 | * in the image URI box, put in the exact same image name you used in the previous step (e.g. /alertmodule:0.0.1-amd64) 167 | * leave the other defaults and click "Save" 168 | * back on the "Set Modules" blade, click "next" 169 | * on the "specify routes" blade, replace the default with the following: 170 | 171 | ```json 172 | { 173 | "routes": { 174 | "toFormatterFromDevices": "FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO BrokeredEndpoint(\"/modules/formattermodule/inputs/input1\")", 175 | "toASAJob": "FROM /messages/modules/formattermodule/outputs/output1 INTO BrokeredEndpoint(\"/modules/edgeASAJob/inputs/inputFromHub\")", 176 | "toAlerts": "FROM /messages/modules/edgeASAJob/outputs/asaAlertTemp INTO BrokeredEndpoint(\"/modules/alertmodule/inputs/input1\")", 177 | "asaToIoTHub": "FROM /messages/modules/edgeASAJob/outputs/asaAggregatedTemp INTO $upstream", 178 | "asaAlertsToIoTHub": "FROM /messages/modules/edgeASAJob/outputs/asaAlertTemp INTO $upstream" 179 | } 180 | } 181 | ``` 182 | 183 | * replace "alertmodule" above (in two places) with the name of your module, case-sensitive, that you used above if different from "alertmodule". Ditto for edgeASAJob and formattermodule 184 | 185 | * the first route above, takes any message that does not come from a "module" and routes it into the input of our Formatter Module. In other words, it takes messages that comes from downstream IoT devices and routes them into our formatter module. It also keeps messages that comes from our formatter module from being routed back into itself. 186 | * the second route takes the output from our Formatter Module and routes it up to IoT Hub in the cloud 187 | 188 | * Click "next" and then "finish" in the Azure portal 189 | 190 | ### Test our module 191 | 192 | After a few seconds, the module should be downloaded and deployed to our IoT Edge runtime. You can confirm this by opening a command prompt and typing "docker ps". You should see all of the previous modules running, the edgeAgent, edgeHub, the formatterModule, the ASA module and our new AlertModule. You can view the logs of any of them by running "docker logs -f \" to make sure they are working. 193 | 194 | As in the previous modules, start the python script (or .NET Core app) that represents our IoT Device to get messages flowing into the system. 195 | 196 | Once that is running, you can use "docker logs -f alertModule" (or whatever you named your module) to see its logs. You won't see anything yet. 197 | 198 | Now hold your finger on the DHT22 temperature sensor to drive temp above 80. Once it crosses above 80, you should see the Alert come through the docker logs for the alertModule, the DM call come through in the debug output of the python (or dotnet) IoT Device, and the onboard LED on the Arduino, after a few seconds, light up. If you release the temperature sensor and the temperature drops back below 80, you should see the process repeat to turn the LED back off. 199 | 200 | In VS Code, under the "IOT HUB DEVICES" section, like before, you should be able to right click on your __**IoT Edge device**__ (note, this is different than before), and choose "Start Monitoring D2C Messages" and see the alert messages flow through to IoT Hub as well if you repeat the process of heating the temperature sensor up. 201 | 202 | Congratulations - You are done! You now have: 203 | 204 | * data coming from a physical IoT device flowing into IoT Edge 205 | * an Edge module that intercepts and reformats that data 206 | * Streaming Analytics on the edge that pre-aggregates the data as well as generates "local" alerts when a dangerous high temperature situation occurs 207 | * a module that takes the 'high temp' alerts and uses them to invoke an action on the IoT Device in question. -------------------------------------------------------------------------------- /module3/README.MD: -------------------------------------------------------------------------------- 1 | # Azure IoT Edge Hands On Labs - Module 3 2 | 3 | Created and maintained by the Microsoft Azure IoT Global Black Belts 4 | 5 | ## Introduction 6 | 7 | For this step of the lab, we are going to create an IoT Edge module that take the raw CSV format provided by our IoT Device, converts it to JSON, and then puts the messages back on the edge Hub for further processing. 8 | 9 | We will develop our module in C# using .NET Core. .NET Core is the cross-platform version of Microsoft's .NET framework. The module and image we develop in this section can be used, unchanged, on x86/x64 based Linux distributions, and can be cross compiled for ARM distributions as well. 10 | 11 | We are primarily using C# and .NET Core for this lab because it is the most completely 'ready' language in terms of tooling at the time the labs are being written (during public preview). However, by General Availability time for IoT Edge, you will be able to develop IoT Edge modules in any supported Azure IoT language, including C, C#, Java, Node, and Python. 12 | 13 | ## Developing our module 14 | 15 | ### Install the following VS Code Extensions 16 | 17 | Click on the "extensions" tab in VS Code and install the following: 18 | 19 | #### Azure IoT Edge extention 20 | 21 | Search for the "Azure IoT Edge" extension by Microsoft. Install it. 22 | 23 | #### C# for Visual Studio Code 24 | 25 | Search for "C# for Visual Studio Code (powered by OmniSharp)" extension by Microsoft. Install it. 26 | 27 | #### Docker 28 | 29 | Search for "Docker" extension by Microsoft. Install it. 30 | 31 | #### Restart 32 | 33 | Reload VS Code. 34 | 35 | ### Creating the module "skeleton" 36 | 37 | We will use VS Code to develop our module. 38 | 39 | * in VS Code, click on File -> Open Folder and navigate to the c:\edge folder we created before 40 | * hit CTRL and + ` to open the Integrated Terminal window in VS Code. 41 | * We will create the "scaffolding" for our IoT Edge module using the IoT Edge module template provided by the IoT Edge product team. To install it, in the integrated terminal, run the following command: 42 | 43 | ``` 44 | dotnet new -i Microsoft.Azure.IoT.Edge.Module 45 | ``` 46 | * now we are ready to create our project. in the integrated terminal, run the following command (where \ is the user name for Docker Hub that you created earlier) 47 | ``` 48 | dotnet new aziotedgemodule -n FormatterModule -r /formattermodule 49 | ``` 50 | * Open the Program.cs file to view the code. Review the boiler-plate code to understand what it does. A few notes: 51 | * The main funtion retrieves the 'connection string' for the module from an environment variable passed into it's docker container by the edge Agent when it creates the container. This connection string is for the module to connect to the local edge Hub instance. Main called "Init" to initiate the connection to the local Hub and set up any callbacks. 52 | * The edge Agent also passes in the necessary cert for a connection to the edge Hub that the module must 'trust' before it can connect (for TLS). This cert is retreived and installed by the InstallCerts method 53 | * the Init method creates an instance of the Device Client class (which is the exact same one you would use to connect to IoT Hub in the cloud) and connects using the connection string passed in from the egde Agent. The Init method then sets any callbacks that will be raised whenever a message is routed to this module (on a named "input") or when module-twin changes happen 54 | * The PipeMessage function is an example implementation of a "listener" for messages to be routed to this module. In the sample implementation, we are basically getting the content of the message and any user-defined meta-data properties, and echoing them back on a new message. We are then marking the current message as "complete" so the edge runtime knows we are done with it. We will be modifying this sample method to implement our message 'formatter' 55 | 56 | ### Modify the sample implementation 57 | 58 | Now lets modify the sample code to implement our Formatter module. 59 | 60 | * in Program.cs, in the "using" section above the Program class, add the two following 'using' statements 61 | 62 | ```CSharp 63 | using Newtonsoft.Json; 64 | ``` 65 | 66 | * above the "Program" class, add the C# class that will represent our message we want to publish to the Hub 67 | 68 | ```CSharp 69 | class Telemetry 70 | { 71 | public string deviceID; 72 | public float temperature; 73 | public float humidity; 74 | } 75 | ``` 76 | 77 | > Note: there is a temporary bug in the certificate validation code for IoT Edge. The below code change is necessary to work around that bug 78 | 79 | * Temporarily we will be bypassing certicate validation in our module. So do so, locate this line of code at the top of the "Main" function 80 | 81 | ```CSharp 82 | bool bypassCertVerification = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); 83 | ``` 84 | 85 | and replace it with 86 | 87 | ```CSharp 88 | bool bypassCertVerification = true; 89 | ``` 90 | 91 | * the balance of our work will be in the PipeMessage function. the top part of the function, which gets the "Device Client" instance that is stored in Context and makes sure it's valid, and that opens the message and gets it's content as a string, is boiler-plate and is fine for our purposes. The work we will be doing is inside the "if" block below (which checks to make sure we don't have an empty message): 92 | 93 | ```CSharp 94 | if (!string.IsNullOrEmpty(messageString)) 95 | { 96 | ..... 97 | } 98 | ``` 99 | 100 | * replace the code within the ````if```` block above, with the below code 101 | 102 | ```CSharp 103 | // if our message isn't 11 characters long (xx.xx,yy.yy) or a comma in the 6th position 104 | // then it's not a message we are interested in. 105 | if((!(messageString.Length == 11)) || !(messageString.Substring(5,1) == ",")) 106 | { 107 | Console.WriteLine("Not a message that interests this module."); 108 | return MessageResponse.Completed; 109 | } 110 | 111 | // split the CSV message into its two parts 112 | // humidity is first, temp second 113 | string[] parts = messageString.Split(","); 114 | 115 | // create and populate our new message content 116 | Telemetry t = new Telemetry(); 117 | t.deviceID = message.ConnectionDeviceId; 118 | t.humidity = float.Parse(parts[0]); 119 | t.temperature = float.Parse(parts[1]); 120 | 121 | // serialize to a string 122 | string newMessage = JsonConvert.SerializeObject(t); 123 | 124 | // create a new IoT Message object and copy 125 | // any properties from the original message 126 | var pipeMessage = new Message(Encoding.ASCII.GetBytes(newMessage)); 127 | foreach (var prop in message.Properties) 128 | { 129 | pipeMessage.Properties.Add(prop.Key, prop.Value); 130 | } 131 | 132 | // send the data to the edge Hub on a named output (for routing) 133 | await deviceClient.SendEventAsync("output1", pipeMessage); 134 | Console.WriteLine($"Converted message sent({counter}): {newMessage}"); 135 | ``` 136 | 137 | * the code above does the following things 138 | * some rudimentary checking to make sure we have a message in the right format 139 | * disassembles the humidity and temp values from the CSV input 140 | * creates a new message using these values and serializes as JSON 141 | * copies any user-defined metadata properties from the original input message to the new message 142 | * send the message back out to the hub on named output 143 | * marks the original message as "complete" so that the Hub knows we successfully processed it and it does not need to be re-sent 144 | 145 | * Save your changes to the Program.cs file 146 | 147 | ## Deploying our module 148 | 149 | Now that our module is created, we need to deploy it to our Edge device and get our messages routed through it. 150 | 151 | ### Log into Docker 152 | 153 | The first step is to log into Docker in the Terminal window. 154 | 155 | ```` 156 | docker login -u -p 157 | ```` 158 | 159 | ### Upload the image to Docker 160 | 161 | In VS Code explorer: 162 | 163 | * Right-click the module.json file and click "Build and Push IoT Edge module Docker Image". 164 | * In the pop-up dropdown box at the top of the VS Code window, select 'amd64' (Linux container). 165 | 166 | VS Code then builds your code, containerize the ````FormatterModule.dll```` and push it to the container registry you specified. 167 | 168 | Our module is now in Docker with the tag ````0.0.1-amd64```` 169 | 170 | 171 | ## Deploy Edge module 172 | 173 | In this section, we will get the module created above deployed and view the results. 174 | 175 | * in the Azure portal, navigate to your IoT Hub, click on IoT Edge Devices (preview) on the left nav, click on your IoT Edge device 176 | * click on "Set Modules" in the top menu bar. 177 | * In the Set Modules blade, click on "Add IoT Edge Module" 178 | * In the "IoT Edge Modules" dialog, give your module a name (for example: formattermodule). Remember the name you used, including the proper 'case' of the letters, as we'll need that when we set the routes in the next step. 179 | * in the image URI box, put in the exact same image name you used in the previous step (e.g. \/formattermodule:0.0.1-amd64) 180 | * leave the other defaults and click "Save" 181 | * back on the "Set Modules" blade, click "next" 182 | * on the "specify routes" blade, replace the default with the following: 183 | 184 | ``` 185 | { 186 | "routes": { 187 | "toFormatterFromDevices": "FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO BrokeredEndpoint(\"/modules/formattermodule/inputs/input1\")", 188 | "toIoTHub": "FROM /messages/modules/formattermodule/outputs/output1 INTO $upstream" 189 | } 190 | } 191 | ``` 192 | * replace "formattermodule" above (in two places) with the name of your module, case-sensitive, that you used above if different than 'formattermodule' 193 | 194 | * the first route above, takes any message that does not come from a "module" and routes it into the input of our Formatter Module. In other words, it takes messages that comes from downstream IoT devices and routes them into our formatter module. It also keeps messages that comes from our formatter module from being routed back into itself. 195 | * the second route takes the output from our Formatter Module and routes it up to IoT Hub in the cloud 196 | 197 | * Click "next" and then "finish" in the Azure portal 198 | 199 | ### Test our module 200 | 201 | After a few seconds, the module should be downloaded and deployed to our IoT Edge runtime. You can confirm this by opening a command prompt and typing "docker ps". You should see three modules running, the edgeAgent, edgeHub, and our new formatterModule. You can view the logs of any of them by running "docker logs -f \" to make sure they are working. 202 | 203 | As in the previous module, start the python script (or .NET Core app, if you did that option) that represents our IoT Device to get messages flowing into our formatter module. 204 | 205 | Once that is running, you can use "docker logs -f formatterModule" (or whatever you named your module) to see its logs. You should see debug output indicating that it is receiving the CSV input, and outputing our new JSON module. 206 | 207 | In VS Code, under the "IOT HUB DEVICES" section, like before, you should be able to click on your __**IoT Edge device**__ (note, this is different than before), and choose "Start Monitoring D2C Messages" and see our new JSON formatted messages flowing. 208 | 209 | __** NOTE: Now that we have an edge module "in between" our IoT device and IoT Hub in the cloud, the messages no longer appears as though it comes from the original IoT Device, but rather from our Edge device now. This is an important distinction. This is one of the reasons also, that our Formatter Module snags the original deviceID and embeds it in our message (we could have also put it in the user-defined metadata for the message). Otherwise, the original device origin would be lost.**__ 210 | 211 | Stop the python script (CTRL-C) (or hit \ if you used the .NET Core app) while we work on the next module 212 | 213 | Ok - now we have messages flowing from our IoT Device and being translated to JSON and sent to IoT Hub. However, the messages are flowing at the original high rate of our "dumb" IoTHub device. Now we are going to add the capability to aggregate the data at the edge, as well as determine when a "high temperature" alert condition occurs (module 4) and take local action (module 5). 214 | 215 | To continue with module 4, click [here](/module4) 216 | -------------------------------------------------------------------------------- /module2/README.dotnet.md: -------------------------------------------------------------------------------- 1 | # Azure IoT Edge Hands On Labs - Module 2 2 | 3 | Created and maintained by the Microsoft Azure IoT Global Black Belts 4 | 5 | ## KNOW BEFORE YOU START 6 | 7 | This version of module2 uses .NET Core for our "IoT Device". If you have trouble with it, or simply prefer python, there is an alternate ".NET Core" implementation [here](./README.md) 8 | 9 | ## Introduction 10 | 11 | For this step of the lab, we are going to create our "IoT Device". For the labs, we wanted to leverage a physical device to make the scenario slightly more realistic (and fun!). 12 | 13 | __**NOTE: Because of easier logistics of setup given a large number of students, we are leveraging Windows desktops for our 'Edge devices' in this lab. If we were doing this on a physical Linux device (like a Raspberry Pi), we would develop an Edge "module" to talk to the USB port containing our Arduino device and just map that port into the docker container running that module via the --devices paramter. However, there is a current limitation in Docker for Windows that doesn't let us do that on a Windows host. So we use an intermediate dumb IoT "device" that reads the serial/USB port and connects and sends that data to IoT Edge.**__. The Docker issue is documented [here](https://github.com/docker/for-win/issues/1018). Feel free to go weigh in on the importance of this issue if you think it will affect you. 14 | 15 | Ok, let's get started... 16 | 17 | ## Create Arduino device 18 | 19 | ### Connect device and ensure basic operation 20 | 21 | 1. Launch the Arduino Desktop App. Upon launching you will be presented an empty project called a “sketch”. 22 | 23 | ![ArduinoIDE](/images/m2bArduino4.png) 24 | 25 | 2. Connect the Arduino device to the workstation with the USB cable. (Note: the Arduino device can get power via either USB or an external power supply. For the purposes of this workshop we’ll be getting power via USB) 26 | 27 | 3. In the Arduino IDE you must select your device as your deployment target. Do this from the Tools -> Port menu: 28 | 29 | ![ArduinoIDE](/images/m2bArduino5.png) 30 | 31 | 4. Now that the device is setup in the IDE, you can open and deploy a sample sketch. From the File -> Examples -> 01.Basics menu open the “Blink” sketch. 32 | 33 | ![ArduinoIDE](/images/m2bArduino6.png) 34 | 35 | 5. Click the "Upload" button to load the sketch to the device. After the sketch has deployed look at your Arduino to validate you have a blinking LED (once per second). 36 | 37 | ### Assemble device 38 | 39 | In this section, we will assemble the IoT device out of the arduino and DHT22 temp/humidity sensor 40 | 41 | 1. __**Disconnect the Arduino from your workstation!!**__. Note this step is very important to ensure there is no electric charge running through the device while we’re assembling. 42 | 43 | 2. With the provided jumper wires and breadboard assemble the Arduino using the following schematic. ** please note the diagram is logical and not to scale. The first and second pins cannot really be separated like shown ** 44 | 45 | 46 | __** UPDATE - the DHT22 sensors you received for this lab may differ from the picture. If your sensor has only 3 pins, then that's fine. Just connect the pin with the "+" next to it to the 3.3v pin on the Arduino device, connect the 'middle' pin marked 'out' to the digital pin '2' on the Arduino, and the pin marked "-" to the GND (ground) pin on the Arduino**. For this particular type of DHT22, it has a built in resistor so you don't need the resistor shown on the diagram **__ 47 | 48 | 49 | ![schematic](/images/m2bArduino7.png) 50 | 51 | This diagram may seem complicated, so let’s deconstruct it a bit. 52 | 53 | 3. The black wire is the ground wire; it runs to the right most pin on the DHT sensor. 54 | 4. The red wire provides power; it runs to the left most pin on the DHT sensor. 55 | 5. The green wire is the signal wire it runs to the pin adjacent to the power lead. 56 | 6. The resistor between pins 1 and 2 of the DHT sensor is called a "pull up" resistor. It essentially just ensures that, during times we are not actively reading the sensor, the pin is "pulled up" to 5V and not electrically "bouncing around" freely. This helps cut down on communication errors between the device and sensor. __**Note that resistors are not directional, so it doesn't matter which direction you plug the resistor into the breadboard. Also note that your resistor with your DHT kit likely won't match the color codes on the screenshot (it's probably brown-black-orange). Either way, use the resistor that came with the kit.**__ 57 | 58 | ### Develop sketch to read sensor and send across serial 59 | 60 | In this section, we will load and execute the arduino "code" to talk to the DHT sensor and send the temperature and humidity data across the serial port. 61 | 62 | 1. Plug your device back in to your workstation via USB. 63 | 64 | 2. Open the dhtSensorSketch.ino sketch in the Arduino IDE from the module2\dhtSensorSketch folder 65 | 66 | 3. In order to use the sensor we first need to download a library for simplifying communication with the device. In the Arduino IDE select “Manage Libraries” from the Sketch -> Include Library menu. 67 | 68 | ![library install](/images/m2bArduino8.png) 69 | 70 | 4. From the library manager window search for “DHT”, select the second option “DHT sensor library by Adafruit” library, and click “Install”. Repeat this process to install the "Adafruit Unified Sensor" library. 71 | 72 | ![library install](/images/m2bArduino9.png) 73 | 74 | 5. When the install is complete close the Library Manager window. 75 | 76 | 6. Deploy the code to the Arduino device (second button from the left on the command bar) 77 | 78 | ![Deploy](/images/m2bArduino10.png) 79 | 80 | 7. Open the "Serial Monitor" tool and make sure that you are getting valid humidity and temperature readings. Place your thumb and index finger aorund the sensor and ensure the values change 81 | 82 | ![Serial monitor](/images/m2bArduino11.png) 83 | 84 | 8. Close the Serial Monitor (feel free to close the Arduino IDE as well - we are done with it). If you do not close the Serial Monitor, it "holds on to" the COM port and we will get an error later trying to read from it. 85 | 86 | ## Create "IoT Device" 87 | 88 | Per the note about needing an intermediate IoT device to talk to the serial port and forward the messages on, we have a "dumb" IoT Device that reads the CSV-formatted data fron the serial/USB port and sends it to IoT Edge 89 | 90 | For our device, we will leverage a .NET Core console app that emulates our IoT Device. The device leverages our C# Azure IoT SDK to connect to the hub. 91 | 92 | ### setup libraries and pre-requisites 93 | 94 | 1. To represent our device in IoT Hub, we need to create an IoT Device 95 | * in the Azure portal, for your IoT Hub, click on "IoT Devices" in the left-nav (note, this is different than the "IoT Edge Devices" we used previously) 96 | * click on "+Add Device" to add a new device. Give the device a name and click "create" 97 | * once the device is created, you will see it appear in the list of devices. Click on the device you just created to get to the details screen. 98 | * capture (in notepad) the Connection String - Primary Key for your IoT device, we will need it in a moment. This is known later as the "IoT Device Connection String" 99 | * __**finally, note the device is created in an initial state of 'Disabled'. Click on the "Enable" button to enable it.**__ 100 | 101 | 2. We need to fill in a couple of pieces of information into our dotnet app. 102 | 103 | Run VS Code and click on File - Open Folder. Open the c:\azure-iot-edge-hol folder. Under the /module2/dotnet/readserial folder, open Progam.cs. 104 | 105 | * In the line of code below 106 | 107 | ```CSharp 108 | static string PortName = ""; // e.g. "COM3" 109 | ``` 110 | 111 | replace "Port name" with the serial port your arduino device is plugged into (e.g "COM3"), which you can find in Windows Device Manager 112 | 113 | * In the line below 114 | 115 | ```CSharp 116 | static string ConnectionString = ""; 117 | ``` 118 | 119 | put your "IoT Device connection string" (captured just above) in the quotes. Onto the end of your connection string, append ";GatewayHostName=mygateway.local". This tells our app/IoT Device to connect to the specified IoTHub in it's connection string, but to do so __**through the specified Edge gateway**__ 120 | 121 | Hit CTRL-S to save Program.cs 122 | 123 | Ok, we now have our device ready, so let's get it connected to the Hub 124 | 125 | ## Start IoT Edge, connect device, and see data flowing through 126 | 127 | In this section, we will get the device created above connected to IoT Edge and see the data flowing though it. 128 | 129 | * in the Azure portal, navigate to your IoT Hub, click on IoT Edge Devices (preview) on the left nav, click on your IoT Edge device 130 | * click on "Set Modules" in the top menu bar. Later, we will add a customer module here, but for now, we are just going to set a route to route all data to IoT Hub, so click "Next" 131 | * on the 'routes' page, make sure the following route is shown, if not, enter it. 132 | 133 | ```json 134 | { 135 | "routes": { 136 | "route":"FROM /* INTO $upstream" 137 | } 138 | } 139 | ``` 140 | 141 | click 'Next', and click 'Submit' 142 | 143 | * $upstream is a special route destination that means "send to IoT Hub in the cloud". So this route takes all messages (/*) and sends to the cloud. This lets us, at this stage in the lab, confirm that Edge is working end-to-end before we move onto subsequent modules. 144 | 145 | ### confirm IoT Edge 146 | 147 | The running instance of IoT Edge should have gotten a notification that it's configuration has changed. 148 | 149 | If you run 'docker ps' again, you should see a new module/container called "edgeHub' running. This is the local IoT Hub-like engine that will store and forward our messages and act like a local IoTHub to our downstream devices 150 | 151 | if you run 'docker logs -f edgeHub', you should see that the Hub has successfully created a route called "route' and is up and listening on port 8883. (the TLS port for MQTT locally) 152 | 153 | The edge device is now ready for our device to connect. 154 | 155 | ### Monitor our IoT Hub 156 | 157 | In VS Code, click on the 'Extensions' tab on the left nav. Search for an install the "Azure IoT Toolkit" by Microsoft. Once installed (reload VS Code, if necessary), click back on the folder view and you should see a new section called "IOT HUB DEVICES" (on the left hand side, at the bottom, below all the 'files'). Hover over it and you should see three dots "...". Click on that and click "Set IoT Hub Connection String". You should see an Edit box appear for you to enter a connection string. Go back to notepad where we copied the connection strings earlier, and copy/paste the "IoT Hub level" (the 'iothubowner') connection string from earlier into the VS Code edit box and hit ok. 158 | 159 | After a few seconds, a list of IoT Device should appear in that section. Once it does, find the IoT Device (not the edge device) that is tied to your "IoT Device" app. Right click on it and select "Start monitoring D2C messages". This should open an output window in VS Code and show that it is listening for messages. 160 | 161 | ### start the local IoT device 162 | 163 | open a new command prompt and CD to the module2/dotnet/readserial folder. Run the following command to 'run' our IoT device. 164 | 165 | To build our app, we need to run the following commands: 166 | 167 | ```cmd 168 | dotnet restore 169 | 170 | dotnet build 171 | ``` 172 | 173 | Once successfully built, we run our app by executing: 174 | 175 | ```cmd 176 | dotnet run 177 | ``` 178 | 179 | Once running successfully, you should see debug output indicating that the device was connected to the "IoT Hub" (in actuality it is connected to the edge device) and see it starting reading and sending humidity and temperature messages. 180 | 181 | ### Observe D2C messages 182 | 183 | In the VS Code output window opened earlier, you should see messages flowing thought the hub. These messages have come from the device, to the local Edge Hub and been forwarded to the cloud based IoT Hub in a store-and-forward fashion (i.e. transparent gateway). Please note that there may be some delay before you see data in the monitor. 184 | 185 | In VS Code, right click on your IoT Device and click on "Stop Monitoring D2C Messages". 186 | 187 | 188 | ### test Direct Method call 189 | 190 | Finally, we also want to test making a Direct Method call to our IoT Device. Later, this functionality will allow us to respond to "high temperature" alerts by taking action on the device. For now, we just want to test the connectivity to make sure that edgeHub is routing Direct Method calls propery to our device. To test: 191 | 192 | * in VS Code, in the "IOT HUB DEVICES" section, right click on your IoT Device and click "Invoke Direct Method". 193 | * in the edit box at the top for the method to call type "ON" (without the quotes) and hit \ 194 | * in the edit box for the payload, just hit \, as we don't need a payload for our method 195 | 196 | You should see debug output in the dotnet app that is our IoT Device indicating that a DM call was made, and after a few seconds, the onboard LED on the device should light up. This is a stand-in for whatever action we would want to take on our real device in the event of an "emergency" high temp alert. 197 | 198 | * repeat the process above, sending "OFF" as the command to toggle the LED back off. 199 | 200 | in the command prompt runing your dotnet app script, hit \ to stop the app 201 | 202 | ## Summary 203 | 204 | The output of module is still the raw output of the device (in CSV format). We've shown that we can connect a device through the edgeHub to IoT Hub in the cloud. In the next labs, we will add modules to re-format the data as JSON, as well as aggregate the data and identify and take local action on "high temperature" alerts. 205 | 206 | To continue with module 3, click [here](/module3) 207 | -------------------------------------------------------------------------------- /module2/README.md: -------------------------------------------------------------------------------- 1 | # Azure IoT Edge Hands On Labs - Module 2 2 | 3 | Created and maintained by the Microsoft Azure IoT Global Black Belts 4 | 5 | ## KNOW BEFORE YOU START 6 | 7 | This version of module2 uses python for our "IoT Device". If you have trouble with it, or simply prefer .NET/C#, there is an alternate ".NET Core" implementation [here](./README.dotnet.md) 8 | 9 | 10 | 11 | # PLEASE NOTE 12 | 13 | Currently, the integration between our python device client and Azure IoT Edge is temporarily broken due to invalid TLS cert validation (hey, it's preview, right?). Please use the .NET Core IoT "leaf" client available [here](./README.dotnet.md) instead until further notice. 14 | 15 | ----------------------------------------------------------------------------------------- 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ## Introduction 25 | 26 | For this step of the lab, we are going to create our "IoT Device". For the labs, we wanted to leverage a physical device to make the scenario slightly more realistic (and fun!). 27 | 28 | __**NOTE: Because of easier logistics of setup given a large number of students, we are leveraging Windows desktops for our 'Edge devices' in this lab. If we were doing this on a physical Linux device (like a Raspberry Pi), we would develop an Edge "module" to talk to the USB port containing our Arduino device and just map that port into the docker container running that module via the --devices paramter. However, there is a current limitation in Docker for Windows that doesn't let us do that on a Windows host. So we use an intermediate dumb IoT "device" that reads the serial/USB port and connects and sends that data to IoT Edge.**__. The Docker issue is documented [here](https://github.com/docker/for-win/issues/1018). Feel free to go weigh in on the importance of this issue if you think it will affect you. 29 | 30 | Ok, let's get started... 31 | 32 | ## Create Arduino device 33 | 34 | ### Connect device and ensure basic operation 35 | 36 | 1. Launch the Arduino Desktop App. Upon launching you will be presented an empty project called a “sketch”. 37 | 38 | ![ArduinoIDE](/images/m2bArduino4.png) 39 | 40 | 2. Connect the Arduino device to the workstation with the USB cable. (Note: the Arduino device can get power via either USB or an external power supply. For the purposes of this workshop we’ll be getting power via USB) 41 | 42 | 3. In the Arduino IDE you must select your device as your deployment target. Do this from the Tools -> Port menu: 43 | 44 | ![ArduinoIDE](/images/m2bArduino5.png) 45 | 46 | 4. Now that the device is setup in the IDE, you can open and deploy a sample sketch. From the File -> Examples -> 01.Basics menu open the “Blink” sketch. 47 | 48 | ![ArduinoIDE](/images/m2bArduino6.png) 49 | 50 | 5. Click the deploy button to load the sketch to the device. After the sketch has deployed look at your Arduino to validate you have a blinking LED (once per second). 51 | 52 | ### Assemble device 53 | 54 | In this section, we will assemble the IoT device out of the arduino and DHT22 temp/humidity sensor 55 | 56 | 1. __**Disconnect the Arduino from your workstation!!**__. Note this step is very important to ensure there is no electric charge running through the device while we’re assembling. 57 | 58 | 2. With the provided jumper wires and breadboard assemble the Arduino using the following schematic. ** please note the diagram is logical and not to scale. The first and second pins cannot really be separated like shown ** 59 | 60 | 61 | __** UPDATE - the DHT22 sensors you received for this lab may differ from the picture. If your sensor has only 3 pins, then that's fine. Just connect the pin with the "+" next to it to the 3.3v pin on the Arduino device, connect the 'middle' pin marked 'out' to the digital pin '2' on the Arduino, and the pin marked "-" to the GND (ground) pin on the Arduino**. For this particular type of DHT22, it has a built in resistor so you don't need the resistor shown on the diagram **__ 62 | 63 | 64 | ![schematic](/images/m2bArduino7.png) 65 | 66 | This diagram may seem complicated, so let’s deconstruct it a bit. 67 | 68 | 3. The black wire is the ground wire; it runs to the right most pin on the DHT sensor. 69 | 4. The red wire provides power; it runs to the left most pin on the DHT sensor. 70 | 5. The green wire is the signal wire it runs to the pin adjacent to the power lead. 71 | 6. The resistor between pins 1 and 2 of the DHT sensor is called a "pull up" resistor. It essentially just ensures that, during times we are not actively reading the sensor, the pin is "pulled up" to 5V and not electrically "bouncing around" freely. This helps cut down on communication errors between the device and sensor. __**Note that resistors are not directional, so it doesn't matter which direction you plug the resistor into the breadboard. Also note that your resistor with your DHT kit likely won't match the color codes on the screenshot (it's probably brown-black-orange). Either way, use the resistor that came with the kit.**__ 72 | 73 | ### Develop sketch to read sensor and send across serial 74 | 75 | In this section, we will load and execute the arduino "code" to talk to the DHT sensor and send the temperature and humidity data across the serial port. 76 | 77 | 1. Plug your device back in to your workstation via USB. 78 | 79 | 2. Open the dhtSensorSketch.ino sketch in the Arduino IDE from the module2\dhtSensorSketch folder 80 | 81 | 3. In order to use the sensor we first need to download a library for simplifying communication with the device. In the Arduino IDE select “Manage Libraries” from the Sketch -> Include Library menu. 82 | 83 | ![library install](/images/m2bArduino8.png) 84 | 85 | 4. From the library manager window search for “DHT”, select the second option “DHT sensor library by Adafruit” library, and click “Install”. Repeat this process to install the "Adafruit Unified Sensor" library. 86 | 87 | ![library install](/images/m2bArduino9.png) 88 | 89 | 5. When the install is complete close the Library Manager window. 90 | 91 | 6. Deploy the code to the Arduino device (second button from the left on the command bar) 92 | 93 | ![Deploy](/images/m2bArduino10.png) 94 | 95 | 7. Open the "Serial Monitor" tool and make sure that you are getting valid humidity and temperature readings. Place your thumb and index finger aorund the sensor and ensure the values change 96 | 97 | ![Serial monitor](/images/m2bArduino11.png) 98 | 99 | 8. Close the Serial Monitor (feel free to close the Arduino IDE as well - we are done with it). If you do not close the Serial Monitor, it "holds on to" the COM port and we will get an error later trying to read from it. 100 | 101 | ## Create "IoT Device" 102 | 103 | Per the note about needing an intermediate IoT device to talk to the serial port and forward the messages on, we have a "dumb" IoT Device that reads the CSV-formatted data fron the serial/USB port and sends it to IoT Edge 104 | 105 | For our device, we will leverage a python script that emulates our IoT Device. The device leverages our python Azure IoT SDK to connect to the hub. 106 | 107 | ### setup libraries and pre-requisites 108 | 109 | 1. Because we are in public preview with IoT Edge, we need to leverage a preview version of the python SDK. To install that preview version, open an administrator command prompt and run this command 110 | 111 | ``` 112 | pip install azure-iothub-device-client==1.3.0.0b0 113 | ``` 114 | 115 | 2. Our script leverages the pyserial library for reading from the serial port, so we need to install it. From the command prompt, run 116 | 117 | ``` 118 | pip install pyserial 119 | ``` 120 | 121 | 3. To represent our device in IoT Hub, we need to create an IoT Device 122 | * in the Azure portal, for your IoT Hub, click on "IoT Devices" in the left-nav (note, this is different than the "IoT Edge Devices" we used previously) 123 | * click on "+Add Device" to add a new device. Give the device a name and click "create" 124 | * once the device is created, you will see it appear in the list of devices. Click on the device you just created to get to the details screen. 125 | * capture (in notepad) the Connection String - Primary Key for your IoT device, we will need it in a moment. This is known later as the "IoT Device Connection String" 126 | * __**finally, note the device is created in an initial state of 'Disabled'. Click on the "Enable" button to enable it.**__ 127 | 128 | 4. We need to fill in a couple of pieces of information into our python script. 129 | 130 | Run VS Code and click on File - Open Folder. Open the c:\azure-iot-edge-hol folder. Under the /module2 folder, open the readserial.py script. 131 | 132 | * In the line of code below 133 | 134 | ```Python 135 | ser = serial.Serial('', 9600) 136 | ``` 137 | 138 | replace "serial port" with the serial port your arduino device is plugged into (e.g "COM3") 139 | 140 | * In the line below 141 | 142 | ```Python 143 | connection_string = "" 144 | ``` 145 | put your "IoT Device connection string" (captured just above) in the quotes. Onto the end of your connection string, append ";GatewayHostName=mygateway.local". This tells our Python script/device to connect to the specified IoTHub in it's connection string, but to do so __**through the specified Edge gateway**__ 146 | 147 | Ok, we now have our device ready, so let's get it connected to the Hub 148 | 149 | ## Start IoT Edge, connect device, and see data flowing through 150 | 151 | In this section, we will get the device created above connected to IoT Edge and see the data flowing though it. 152 | 153 | * in the Azure portal, navigate to your IoT Hub, click on IoT Edge Devices (preview) on the left nav, click on your IoT Edge device 154 | * click on "Set Modules" in the top menu bar. Later, we will add a customer module here, but for now, we are just going to set a route to route all data to IoT Hub, so click "Next" 155 | * on the 'routes' page, make sure the following route is shown, if not, enter it. 156 | 157 | ```json 158 | { 159 | "routes": { 160 | "route":"FROM /* INTO $upstream" 161 | } 162 | } 163 | ``` 164 | 165 | click 'Next', and click 'Submit' 166 | 167 | * $upstream is a special route destination that means "send to IoT Hub in the cloud". So this route takes all messages (/*) and sends to the cloud. This lets us, at this stage in the lab, confirm that Edge is working end-to-end before we move onto subsequent modules. 168 | 169 | ### confirm IoT Edge 170 | 171 | The running instance of IoT Edge should have gotten a notification that it's configuration has changed. 172 | 173 | If you run 'docker ps' again, you should see a new module/container called "edgeHub' running. This is the local IoT Hub-like engine that will store and forward our messages and act like a local IoTHub to our downstream devices 174 | 175 | if you run 'docker logs -f edgeHub', you should see that the Hub has successfully created a route called "route' and is up and listening on port 8883. (the TLS port for MQTT locally) 176 | 177 | The edge device is now ready for our device to connect. 178 | 179 | ### Monitor our IoT Hub 180 | 181 | In VS Code, click on the 'Extensions' tab on the left nav. Search for an install the "Azure IoT Toolkit" by Microsoft. Once installed (reload VS Code, if necessary), click back on the folder view and you should see a new section called "IOT HUB DEVICES" (on the left hand side, at the bottom, below all the 'files'). Hover over it and you should see three dots "...". Click on that and click "Set IoT Hub Connection String". You should see an Edit box appear for you to enter a connection string. Go back to notepad where we copied the connection strings earlier, and copy/paste the "IoT Hub level" (the 'iothubowner') connection string from earlier into the VS Code edit box and hit ok. 182 | 183 | After a few seconds, a list of IoT Device should appear in that section. Once it does, find the IoT Device (not the edge device) that is tied to your python script. Right click on it and select "Start monitoring D2C messages". This should open an output window in VS Code and show that it is listening for messages. 184 | 185 | ### start the local IoT device 186 | 187 | open a new command prompt and CD to the module2 folder. Run the following command to 'run' our IoT device 188 | 189 | ```cmd 190 | python -u readserial.py 191 | ``` 192 | 193 | * NOTE: Some recent changes (remember, it's preview :-) ) accidentally dropped a dependency from the azure-iot-device-client python library installed above, specifically the Visual C++ 2015 runtime library. Whether you see this error not will depend somewhat on when you installed the library, and whether or not you have Visual Studio (or something else that uses that library) installed on your box. *IF* you see the error below, you have the problem: 194 | 195 | ![busted_python_lib](/images/python_lib_busted.png) 196 | 197 | * If you see this error, you need to install the VC++ 2015 runtime distribuation, available [here](https://www.microsoft.com/en-us/download/details.aspx?id=48145). Click "Download", select "vc_redist.x86.exe", click "Next", and then execute the installer once downloaded. That should fix the problem. Try re-running the readserial.py script using the command above. 198 | 199 | Once running successfully, you should see debug output indicating that the device was connected to the "IoT Hub" (in actuality it is connected to the edge device) and see it starting reading and sending humidity and temperature messages. 200 | 201 | Your output should look something like the below screenshot. Note that the lines showing the data being sent are interspersed with confirmation messages that it was successfully sent. If your output doesn't look like this (and is, for example, only showing the temp/humidity readings and no confirmation messages), then YOUR PYTHON SCRIPT IS NOT CORRECTLY WORKING WITH EDGE and you need to troubleshoot 202 | 203 | ![python_success](/images/python_success.png) 204 | 205 | 206 | ### Observe D2C messages 207 | 208 | In the VS Code output window opened earlier, you should see messages flowing thought the hub. These messages have come from the device, to the local Edge Hub and been forwarded to the cloud based IoT Hub in a store-and-forward fashion (i.e. transparent gateway). Please note that there may be some delay before you see data in the monitor. 209 | 210 | In VS Code, right click on your IoT Device and click on "Stop Monitoring D2C Messages". 211 | 212 | 213 | ### test Direct Method call 214 | 215 | Finally, we also want to test making a Direct Method call to our IoT Device. Later, this functionality will allow us to respond to "high temperature" alerts by taking action on the device. For now, we just want to test the connectivity to make sure that edgeHub is routing Direct Method calls propery to our device. To test: 216 | 217 | * in VS Code, in the "IOT HUB DEVICES" section, right click on your IoT Device and click "Invoke Direct Method". 218 | * in the edit box at the top for the method to call type "ON" (without the quotes) and hit \ 219 | * in the edit box for the payload, just hit \>, as we don't need a payload for our method 220 | 221 | You should see debug output in the python script that is our IoT Device indicating that a DM call was made, and after a few seconds, the onboard LED on the device should light up. This is a stand-in for whatever action we would want to take on our real device in the event of an "emergency" high temp alert. 222 | 223 | * repeat the process above, sending "OFF" as the command to toggle the LED back off. 224 | 225 | 226 | in the command prompt runing your python script, hit CTRL-C to stop the script. 227 | 228 | ## Summary 229 | 230 | The output of module is still the raw output of the device (in CSV format). We've shown that we can connect a device through the edgeHub to IoT Hub in the cloud. In the next labs, we will add modules to re-format the data as JSON, as well as aggregate the data and identify and take local action on "high temperature" alerts. 231 | 232 | To continue with module 3, click [here](/module3) 233 | --------------------------------------------------------------------------------