├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── general-inquiry.md │ └── problem-report.md ├── LICENSE ├── README.md ├── SECURITY.md ├── debugging └── Dockerfile.amd64.debug ├── eflow-util ├── README.md ├── edge-certificates │ ├── EflowUtil-EdgeCertificates.psm1 │ ├── Get-EdgeCertificates.ps1 │ ├── README.md │ └── Set-EdgeCertificates.ps1 ├── eflow-usbip │ ├── Add-EflowUSBDevices.ps1 │ ├── EflowUtil-Usbip.psm1 │ ├── Get-EflowUSBDevices.ps1 │ ├── README.md │ └── Remove-EflowUSBDevices.ps1 ├── firewall-rules │ ├── EflowUtil-FirewallRules.psm1 │ ├── Get-FirewallRules.ps1 │ ├── README.md │ └── Set-FirewallRules.ps1 └── updateWssdCert.ps1 ├── eflowautodeploy ├── README.md ├── eflow-userconfig-template.json ├── eflow-userconfig.json ├── eflow-userconfig.puml ├── eflowAutoDeploy.png └── eflowAutoDeploy.ps1 ├── eflowremotedeploy ├── README.md └── eflowRemoteDeploy.ps1 └── samples ├── README.md ├── camera-over-rtsp ├── .gitignore ├── CameraRTPStreamerApp │ ├── CameraRTPStreamerApp.cpp │ └── build │ │ ├── CameraRTPStreamerApp.vcxproj │ │ ├── CameraRTPStreamerApp.vcxproj.filters │ │ ├── CameraRTPStreamerApp.vcxproj.user │ │ └── RTSPServer.log ├── Common │ └── inc │ │ ├── NetworkMediaStreamer.h │ │ ├── RTPMediaStreamer.h │ │ └── RTSPServerControl.h ├── NetworkMediaStreamer.sln ├── NetworkMediaStreamerBase │ ├── build │ │ ├── NetworkMediaStreamer.vcxproj │ │ └── NetworkMediaStreamer.vcxproj.filters │ ├── inc │ │ ├── NwMediaStreamSinkBase.h │ │ └── pch.h │ └── src │ │ └── NwMediaStreamSinkBase.cpp ├── README.md ├── RTPMediaStreamer │ ├── build │ │ ├── RTPMediaStreamer.vcxproj │ │ ├── RTPMediaStreamer.vcxproj.filters │ │ └── RTPMediaStreamer.vcxproj.user │ ├── inc │ │ ├── RTPStreamSink.h │ │ └── pch.h │ └── src │ │ ├── RTPMediaSink.cpp │ │ └── RTPStreamSink.cpp ├── RTSPServer │ ├── build │ │ ├── RTSPServer.vcxproj │ │ └── RTSPServer.vcxproj.filters │ ├── inc │ │ ├── RTSPServer.h │ │ ├── RtspSession.h │ │ ├── SocketWrapper.h │ │ └── pch.h │ └── src │ │ ├── RTSPAuthProvider.cpp │ │ ├── RTSPServer.cpp │ │ ├── RtspSession.cpp │ │ └── SocketWrapper.cpp └── docs │ ├── CameraAndResolution.png │ ├── RTSPVideoStreamer.jpg │ └── RTSPVideoStreamer.vsdx ├── edge-ai-welding-demo ├── README.md ├── simulator.md ├── simulator_configs │ ├── configure.py │ ├── datasource.json │ ├── edge_ui.json │ ├── setup_telegraf.bat │ ├── simulator_ui.json │ └── telegraf.conf └── src │ ├── .env │ ├── deployment.template.json │ └── modules │ ├── opcua │ ├── Dockerfile.opcua │ ├── module.json │ └── src │ │ └── server.py │ ├── pipeline │ ├── Dockerfile.pipeline │ ├── models │ │ └── weld_porosity │ │ │ └── FP32 │ │ │ ├── weld-porosity-detection-0001.bin │ │ │ └── weld-porosity-detection-0001.xml │ ├── module.json │ └── src │ │ ├── run.sh │ │ └── weld_porosity.py │ ├── rtspsim │ ├── Dockerfile.rtspsim │ ├── input │ │ └── input.mp4 │ ├── module.json │ └── src │ │ ├── run.sh │ │ └── streamer.py │ └── telegraf │ ├── Dockerfile.telegraf │ ├── module.json │ └── src │ ├── image_server.py │ ├── mqtt_sub.py │ ├── print_count.py │ ├── requirements.txt │ └── telegraf.conf ├── interop-customvision-textmsg-uwpapp ├── Documentation │ ├── Configuring the IoT Edge Device.MD │ ├── Create Certificates for Authentication.MD │ ├── Deploy the Modules onto the IoT Edge Device.MD │ ├── Develop and publish the IoT edge Linux module.MD │ ├── Develop the Windows C# UWP Application.MD │ ├── Images │ │ ├── BuildAndPushError.png │ │ ├── LogError.png │ │ ├── TLS_Error.png │ │ ├── fruitclassifier-sample.png │ │ ├── processingmodule-sample.png │ │ ├── proxymodule-sample.png │ │ ├── uwp-app-message-sample.png │ │ ├── uwp-app-setup-sample.png │ │ └── winapp-sample.png │ ├── Run samples.MD │ ├── Setup Azure IoT Edge for Linux on Windows.MD │ ├── Setup Azure Resources.MD │ └── Troubleshooting.MD ├── README.md ├── customvision │ ├── .gitignore │ ├── DeviceCustomVisionUWPApp │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── Assets │ │ │ ├── LockScreenLogo.scale-200.png │ │ │ ├── SplashScreen.scale-200.png │ │ │ ├── Square150x150Logo.scale-200.png │ │ │ ├── Square44x44Logo.scale-200.png │ │ │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ │ │ ├── StoreLogo.png │ │ │ └── Wide310x150Logo.scale-200.png │ │ ├── CameraRotationHelper.cs │ │ ├── CertificateManager.cs │ │ ├── DeviceCustomVisionUWPApp.csproj │ │ ├── DeviceCustomVisionUWPApp.sln │ │ ├── MainPage.xaml │ │ ├── MainPage.xaml.cs │ │ ├── Package.appxmanifest │ │ ├── Properties │ │ │ ├── AssemblyInfo.cs │ │ │ └── Default.rd.xml │ │ └── pear.jpg │ ├── deployment.debug.template.json │ ├── deployment.template.json │ └── modules │ │ ├── fruitclassifier │ │ ├── .gitignore │ │ ├── Dockerfile │ │ ├── Dockerfile.amd64 │ │ ├── Dockerfile.amd64.debug │ │ ├── README.txt │ │ ├── app │ │ │ ├── app.py │ │ │ ├── labels.txt │ │ │ ├── model.pb │ │ │ ├── predict.py │ │ │ └── requirements.txt │ │ ├── azureml │ │ │ ├── README.txt │ │ │ └── score.py │ │ ├── main.py │ │ ├── module.json │ │ └── requirements.txt │ │ ├── processingmodule │ │ ├── .dockerignore │ │ ├── .gitignore │ │ ├── Dockerfile.amd64 │ │ ├── Dockerfile.amd64.debug │ │ ├── Logger.cs │ │ ├── Program.cs │ │ ├── module.json │ │ └── processingmodule.csproj │ │ └── proxymodule │ │ ├── .gitignore │ │ ├── Dockerfile.amd64 │ │ ├── Dockerfile.amd64.debug │ │ ├── Logger.cs │ │ ├── Program.cs │ │ ├── module.json │ │ └── proxymodule.csproj └── textmsg-uwpapp │ ├── .gitignore │ ├── LeafDeviceUWPApp │ ├── App.xaml │ ├── App.xaml.cs │ ├── Assets │ │ ├── LockScreenLogo.scale-200.png │ │ ├── SplashScreen.scale-200.png │ │ ├── Square150x150Logo.scale-200.png │ │ ├── Square44x44Logo.scale-200.png │ │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ │ ├── StoreLogo.png │ │ └── Wide310x150Logo.scale-200.png │ ├── CertificateManager.cs │ ├── LeafDeviceUWPApp.csproj │ ├── LeafDeviceUWPApp.sln │ ├── MainPage.xaml │ ├── MainPage.xaml.cs │ ├── Package.appxmanifest │ └── Properties │ │ ├── AssemblyInfo.cs │ │ └── Default.rd.xml │ ├── deployment.debug.template.json │ ├── deployment.template.json │ └── modules │ ├── processingmodule │ ├── .dockerignore │ ├── .gitignore │ ├── Dockerfile.amd64 │ ├── Dockerfile.amd64.debug │ ├── Logger.cs │ ├── Program.cs │ ├── module.json │ └── processingmodule.csproj │ └── proxymodule │ ├── .gitignore │ ├── Dockerfile.amd64 │ ├── Dockerfile.amd64.debug │ ├── Logger.cs │ ├── Program.cs │ ├── module.json │ └── proxymodule.csproj ├── interop-textmsg-consoleapp ├── Documentation │ ├── Configuring the IoT Edge Device.MD │ ├── Create Certificates for Authentication.MD │ ├── Deploy the Modules onto the IoT Edge Device.MD │ ├── Develop and publish the IoT edge Linux module.MD │ ├── Develop the Windows C# Console Application.MD │ ├── Images │ │ ├── BuildAndPushError.png │ │ ├── ConsoleAppRunning.png │ │ ├── IoTEdgeList.png │ │ ├── IoTEdgeLogs.png │ │ ├── LogError.png │ │ ├── MicrosoftCert.png │ │ ├── Resolvctl.png │ │ └── TLS_Error.png │ ├── Run the Console Application.MD │ ├── Setup Azure IoT Edge for Linux on Windows.MD │ ├── Setup Azure Resources.MD │ └── Troubleshooting.MD ├── LeafDeviceApp │ ├── CertificateManager.cs │ ├── LeafDeviceApp.csproj │ └── Program.cs ├── README.md ├── deployment.template.json └── modules │ └── CSharpModule │ ├── CSharpModule.csproj │ ├── Dockerfile.amd64 │ ├── Dockerfile.amd64.debug │ ├── Program.cs │ └── module.json ├── networking └── routing │ └── README.md ├── serial ├── README.md ├── scheduled-task-helper.ps1 └── socat-daemon.service └── tpm-read-nv └── Program.cs /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Windows Host OS (please complete the following information):** 27 | - Edition: [e.g. Professional, IoT Enterprise, Server, etc] 28 | - Version: [e.g. build 17763] 29 | - Virtual Machine: [eg. Azure VM, Local VM, None] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general-inquiry.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General Inquiry 3 | about: General inquiry about usage 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Question Summary** 11 | A clear and concise summary of question or goal that you have in mind. 12 | 13 | **Detailed background** 14 | Additional details required to frame the context of your question. 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/problem-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Problem report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the Problem** 11 | A clear and concise description of what the problem. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Windows Host OS (please complete the following information):** 27 | - Edition: [e.g. Professional, IoT Enterprise, Server, etc] 28 | - Version: [e.g. build 17763] 29 | - Virtual Machine: [eg. Azure VM, Local VM, None] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 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 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | █████╗ ███████╗ ██╗ ██╗ ██████╗ ███████╗   ███████╗ ███████╗ ██╗ █████╗ ██╗ ██╗ 4 | ██╔══██╗ ╚════██║ ██║ ██║ ██╔══██╗ ██╔════╝   ██╔════╝ ██╔════╝ ██║ ██╔══██╗ ██║ ██╗ ██║ 5 | ███████║ ███╔═╝ ██║ ██║ ██████╔╝ █████╗    █████╗ █████╗ ██║ ██║ ██║ ╚██╗████╗██╔╝ 6 | ██╔══██║ ██╔══╝ ██║ ██║ ██╔══██╗ ██╔══╝    ██╔══╝ ██╔══╝ ██║ ██║ ██║ ████╔═████║ 7 | ██║ ██║ ███████╗ ╚██████╔╝ ██║ ██║ ███████╗   ███████╗ ██║ ███████╗ ╚█████╔╝ ╚██╔╝ ╚██╔╝ 8 | ╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝   ╚══════╝ ╚═╝ ╚══════╝ ╚════╝ ╚═╝ ╚═╝ 9 | 10 | # Azure IoT Edge for Linux on Windows 11 | Welcome to the home of Azure IoT Edge for Linux on Windows, a composite project enabling the abilty to run Linux-based Edge modules on Windows using a curated virtual machine based on [Azure Linux](https://github.com/microsoft/azurelinux) with [Azure IoT Edge](https://github.com/Azure/iotedge) built-in. 12 | 13 | 14 | _Azure IoT Edge for Linux on Windows supports the following versions:_ 15 | - 1.4 LTS using Azure IoT Edge 1.4 LTS - **Generally Available**. 16 | - [Generally Availability Announcement](https://aka.ms/AzEFLOW-LTS-Blog) 17 | 18 | - Continuous Release (CR) using Azure IoT Edge 1.3 currently in **Public Preview**. 19 | - [Public Preview Announcement](https://azure.microsoft.com/en-us/updates/public-preview-azure-iot-edge-for-linux-on-windows-eflow-update/) 20 | 21 | _Azure IoT Edge for Linux on Windows unsupported versions:_ 22 | 23 | - 1.1 LTS using Azure IoT Edge 1.1 LTS - **End of Life as of December 13, 2022**. 24 | 25 | ## Getting Started 26 | 27 | - [Get Started Now](https://docs.microsoft.com/azure/iot-edge/how-to-install-iot-edge-on-windows) 28 | - [Learn More](https://aka.ms/AzEflow-docs) 29 | - [Sample Codes](./samples) 30 | - [EFLOW Auto Deploy sample](./eflowautodeploy/) 31 | - [EFLOW Remote Deploy sample (Azure Arc/ Microsoft Intune)](./eflowremotedeploy/) 32 | - [Build & Debug IoT Edge Linux modules using EFLOW](https://docs.microsoft.com/azure/iot-edge/tutorial-develop-for-linux-on-windows?view=iotedge-2018-06) 33 | 34 | ## Issues 35 | Issues can be filed in the issues section of either the [iotedge](https://github.com/Azure/iotedge/issues) or [iotedge-eflow](https://github.com/Azure/iotedge-eflow/issues) Github repositories depending on the specific issue that you are experiencing. If you are encountering a production level issue in which you require assistance, we strongly suggest that you [Create an Azure Support Request](https://docs.microsoft.com/en-us/azure/iot-fundamentals/iot-support-help?view=iotedge-2018-06#create-an-azure-support-request). 36 | 37 | ## Feature requests 38 | Feature requests can be filed in our [iotedge-eflow isssues](https://github.com/Azure/iotedge-eflow/issues) page. 39 | 40 | ## Microsoft Open Source Code of Conduct 41 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 42 | 43 | Resources: 44 | 45 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 46 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 47 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 48 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /debugging/Dockerfile.amd64.debug: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build-env 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y --no-install-recommends unzip procps && \ 5 | rm -rf /var/lib/apt/lists/* 6 | 7 | RUN curl -sSL https://aka.ms/getvsdbgsh | bash /dev/stdin -v latest -l ~/vsdbg 8 | 9 | COPY id_rsa.pub ./authorized_keys 10 | RUN mkdir ~/.ssh/ 11 | RUN mv /authorized_keys ~/.ssh/authorized_keys 12 | 13 | RUN apt-get update 14 | RUN apt-get install unzip 15 | RUN apt-get install openssh-server unzip curl -y 16 | RUN apt-get install emacs24-nox -y 17 | 18 | WORKDIR /app 19 | 20 | COPY *.csproj ./ 21 | RUN dotnet restore 22 | 23 | COPY . ./ 24 | RUN dotnet publish -c Debug -o out 25 | 26 | FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim AS base 27 | FROM base 28 | WORKDIR /app 29 | 30 | COPY --from=build-env /app/out ./ 31 | 32 | EXPOSE 22 33 | ENTRYPOINT ["dotnet", "IotEdgeModule1.dll"] 34 | -------------------------------------------------------------------------------- /eflow-util/README.md: -------------------------------------------------------------------------------- 1 | # EFLOW Util PowerShell functions 2 | 3 | Understand EFLOW-Util PowerShell functions that provide extra mechanisms to communicate and interact with the EFLOW VM. 4 | 5 | ### :warning: Important 6 | _The following functions are samples codes that are not meant to be used in production deployments. Furthermore, functions are subject to change and deletion. Make sure you create your own functions based on these samples._. 7 | 8 | | Module | Description | 9 | | --------- | --------------- | 10 | | [EFLOWUtil-EdgeCertificates](./edge-certificates/) | PowerShell functions that provide extra mechanisms to copy and set certificates inside the EFLOW VM. | 11 | | [EFLOWUtil-FirewallRules](./firewall-rules/) | PowerShell functions that provide extra mechanisms to get and set firewall rules of EFLOW VM. | 12 | | [EFLOWUtil-Usbip](./eflow-usbip/) | PowerShell functions that provide extra mechanisms to connect and disconnect USB devices to the EFLOW VM. | 13 | -------------------------------------------------------------------------------- /eflow-util/edge-certificates/EflowUtil-EdgeCertificates.psm1: -------------------------------------------------------------------------------- 1 | <# 2 | Root Module including all the required modules 3 | #> 4 | 5 | # Check for admin privilege first before proceeding... 6 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` 7 | [Security.Principal.WindowsBuiltInRole]::Administrator)) { 8 | Write-Host "Ensure to tun this PowerShell module in Administrator mode!" -ForegroundColor "Red" 9 | return 10 | } 11 | 12 | # If admin privilege, import EFLOW module 13 | Import-Module AzureEflow 14 | 15 | # Source all the powershell scripts for the functions 16 | . $PSScriptRoot\Get-EdgeCertificates.ps1 17 | . $PSScriptRoot\Set-EdgeCertificates.ps1 -------------------------------------------------------------------------------- /eflow-util/edge-certificates/Get-EdgeCertificates.ps1: -------------------------------------------------------------------------------- 1 | function Get-EflowVmEdgeCertificates 2 | { 3 | try 4 | { 5 | # Check IoT Edge version (1.1 or 1.2) 6 | $iotEdgeVersion = Invoke-EflowVmCommand "sudo iotedge version" 7 | 8 | if([string]::IsNullOrEmpty($iotEdgeVersion)) 9 | { 10 | Write-Host "Could not retrieve IoT Edge version" -ForegroundColor "Red" 11 | return 12 | } 13 | 14 | # By default, command is for IoT Edge 1.1 using config.yaml file 15 | $vmCommand = 'sudo cat /etc/iotedge/config.yaml | grep "[[:blank:]]*certificates:" -A4' 16 | 17 | # If IoT Edge = 1.2/1.3/1.4 check for config.toml file 18 | if($iotEdgeVersion -Match "1.2" -Or $iotEdgeVersion -Match "1.3" -Or $iotEdgeVersion -Match "1.4") 19 | { 20 | $vmCommand = 'sudo cat /etc/aziot/config.toml | grep "[[:blank:]]*certificates:" -A4' 21 | } 22 | 23 | $result = Invoke-EflowVmCommand -command $vmCommand -ignoreError 24 | 25 | if([string]::IsNullOrEmpty($result)) 26 | { 27 | return [PSCustomObject]@{ 28 | device_ca_cert = "-" 29 | device_ca_pk = "-" 30 | trusted_ca_certs = "-" 31 | } 32 | } 33 | else 34 | { 35 | return [PSCustomObject]@{ 36 | device_ca_cert = $result[1].Split(":")[1] 37 | device_ca_pk = $result[2].Split(":")[1] 38 | trusted_ca_certs = $result[2].Split(":")[1] 39 | } 40 | } 41 | } 42 | catch [Exception] 43 | { 44 | # An exception was thrown, write it out and exit 45 | Write-Host "Exception caught!!!" -ForegroundColor "Red" 46 | Write-Host $_.Exception.Message.ToString() -ForegroundColor "Red" 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /eflow-util/edge-certificates/README.md: -------------------------------------------------------------------------------- 1 | # EFLOW Util Edge Certificates functions 2 | 3 | Understand EFLOW-Util EdgeCertificates PowerShell functions that provide extra mechanisms to copy and set certificates inside the EFLOW VM. 4 | 5 | ### :warning: Important 6 | _The following functions are samples codes that are not meant to be used in production deployments. Furthermore, functions are subject to change and deletion. Make sure you create your own functions based on these samples._. 7 | 8 | ## Get-EflowVmEdgeCertificates 9 | 10 | The [**Get-EflowVmEdgeCertificates**](./Get-EdgeCertificates.ps1) command checks if IoT Edge is configured to use certificates. If so, it will display the path of the certificates. 11 | This command takes no parameters. It returns an object that contains three properties: 12 | 13 | - Root CA certificate path 14 | - Device CA certificate path 15 | - Private Key path 16 | 17 | ## Set-EflowVmEdgeCertificates 18 | 19 | The [**Set-EflowVmEdgeCertificates**](./Set-EdgeCertificates.ps1) command sets the IoT Edge certificates in the virtual machine. The command handles copying the certificates into the EFLOW VM, assigning the needed permissions, and configuring IoT Edge. Use the optional parameters to define a specific file/folder for configuration. 20 | 21 | | Parameter | Accepted values | Comments | 22 | | --------- | --------------- | -------- | 23 | | _rootCAPath_ | Root CA source path on Windows | Root CA it is the topmost certificate authority for the IoT Edge scenario. | 24 | | _deviceCACertificatePath_ | Device CA Certificate path on Windows | - | 25 | | _deviceCAPrivateKeyPath_ | Device CA Private Key path on Windows | - | 26 | | identityCertDirVm | Certificates folder path on CBL-Mariner (EFLOW VM) | **Optional** | 27 | | _deviceCAPrivateKeyPath_ | Private Key folder path on CBL-Mariner (EFLOW VM) | **Optional** | -------------------------------------------------------------------------------- /eflow-util/eflow-usbip/Add-EflowUSBDevices.ps1: -------------------------------------------------------------------------------- 1 |  function Add-EflowUSBDevices 2 | { 3 | <# 4 | .DESCRIPTION 5 | Connects the USB device with to the EFLOW virutal machine 6 | 7 | .PARAMETER busId 8 | Bus-id assigned by Windows to the USB device 9 | 10 | .PARAMETER hostIp 11 | IP address of the Windows host OS 12 | #> 13 | 14 | param ( 15 | 16 | [Parameter(Mandatory)] 17 | [String] $busId, 18 | 19 | [Parameter(Mandatory)] 20 | [String] $hostIp 21 | ) 22 | 23 | try 24 | { 25 | if (-not ($hostIp -as [IPAddress] -as [Bool])) { 26 | Write-Host "Error: Invalid IP4Address $hostIp" -ForegroundColor Red 27 | return 28 | } 29 | 30 | $usbipd = Get-ChildItem -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' | Get-ItemProperty | Where-Object {$_.DisplayName -eq 'usbipd-win'} 31 | if($usbipd) 32 | { 33 | Write-Host "Ok - USBIP-Win is installed on the Windows host OS" 34 | if ( [bool](Get-Command -Name 'usbipd' -ErrorAction SilentlyContinue)) 35 | { 36 | Write-Host "Ok - USBIP-Win is loaded" 37 | } 38 | else 39 | { 40 | Write-Host "Error - USBIP-Win is not loaded - Reopen the PowerShell session or manually import the command tool" -ForegroundColor "Red" 41 | } 42 | } 43 | else 44 | { 45 | Write-Host "Error - USBIP-Win it's not installed" -ForegroundColor "Red" 46 | return 47 | } 48 | 49 | [String]$eflowVersion = (Get-ChildItem -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' | Get-ItemProperty | Where-Object {$_.DisplayName -eq 'Azure IoT Edge LTS' -or $_.DisplayName -eq 'Azure IoT Edge'}).DisplayVersion 50 | if ([string]::IsNullOrEmpty($eflowVersion)) 51 | { 52 | Write-Host "Error - EFLOW it's no installed in the Windows host OS" -ForegroundColor "Red" 53 | return 54 | } 55 | elseif([int]$eflowVersion.Split(".")[1] -eq 2 -and [int]$eflowVersion.Split(".")[2] -lt 10) 56 | { 57 | Write-Host "Error - EFLOW version $eflowVersion it's not supported" -ForegroundColor "Red" 58 | return 59 | } 60 | elseif([int]$eflowVersion.Split(".")[1] -eq 1 -and [int]$eflowVersion.Split(".")[2] -lt 2207) 61 | { 62 | Write-Host "Error - EFLOW version $eflowVersion it's not supported" -ForegroundColor "Red" 63 | return 64 | } 65 | 66 | Write-Host "Starting sharing the USB device to the EFLOW VM" 67 | usbipd bind --busid=$busId 68 | 69 | Write-Host "Checking the USB device is reachable from the EFLOW VM" 70 | $checkResult = Invoke-EflowVmCommand "sudo usbip list --remote=$hostIp | grep $busId" -ignoreError 71 | if([string]::IsNullOrEmpty($checkResult)){ 72 | Write-Host "Error - The USB device with BusId=$busId could not be reached from the EFLOW VM" -ForegroundColor "Red" 73 | return 74 | } 75 | 76 | Write-Host "Attaching the USB device inside the EFLOW VM" 77 | 78 | Invoke-EflowVmCommand "sudo modprobe vhci-hcd" 79 | Invoke-EflowVmCommand "sudo modprobe usbip-host" 80 | Invoke-EflowVmCommand "sudo modprobe usbip-core" 81 | Invoke-EflowVmCommand "sudo usbip attach --remote=$hostIp --busid=$busId" 82 | 83 | Write-Host "USB $busId was correctly connected to the EFLOW VM" 84 | } 85 | catch [Exception] 86 | { 87 | # An exception was thrown, write it out and exit 88 | Write-Host "Exception caught" -ForegroundColor "Red" 89 | Write-Host $_.Exception.Message.ToString() -ForegroundColor "Red" 90 | return 91 | } 92 | } -------------------------------------------------------------------------------- /eflow-util/eflow-usbip/EflowUtil-Usbip.psm1: -------------------------------------------------------------------------------- 1 | <# 2 | Root Module including all the required modules 3 | #> 4 | 5 | # Check for admin privilege first before proceeding... 6 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` 7 | [Security.Principal.WindowsBuiltInRole]::Administrator)) { 8 | Write-Host "Ensure to tun this PowerShell module in Administrator mode!" -ForegroundColor "Red" 9 | return 10 | } 11 | 12 | # If admin privilege, import EFLOW module 13 | Import-Module AzureEflow 14 | 15 | # Source all the powershell scripts for the functions 16 | . $PSScriptRoot\Get-EflowUSBDevices.ps1 17 | . $PSScriptRoot\Add-EflowUSBDevices.ps1 18 | . $PSScriptRoot\Remove-EflowUSBDevices.ps1 19 | -------------------------------------------------------------------------------- /eflow-util/eflow-usbip/Get-EflowUSBDevices.ps1: -------------------------------------------------------------------------------- 1 | function Get-EflowUSBDevices 2 | { 3 | <# 4 | .DESCRIPTION 5 | List all of the USB devices connected to Windows that could be attached to the EFLOW virutal machine 6 | #> 7 | 8 | try 9 | { 10 | $usbipd = Get-ChildItem -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' | Get-ItemProperty | Where-Object {$_.DisplayName -eq 'usbipd-win'} 11 | if($usbipd) 12 | { 13 | Write-Host "Ok - USBIP-Win is installed on the Windows host OS" 14 | if ( [bool](Get-Command -Name 'usbipd' -ErrorAction SilentlyContinue)) 15 | { 16 | Write-Host "Ok - USBIP-Win is loaded" 17 | } 18 | else 19 | { 20 | Write-Host "Error - USBIP-Win is not loaded - Reopen the PowerShell session or manually import the command tool" -ForegroundColor "Red" 21 | } 22 | } 23 | else 24 | { 25 | Write-Host "Error - USBIP-Win it's not installed" -ForegroundColor "Red" 26 | return 27 | } 28 | 29 | [String]$eflowVersion = (Get-ChildItem -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' | Get-ItemProperty | Where-Object {$_.DisplayName -eq 'Azure IoT Edge LTS' -or $_.DisplayName -eq 'Azure IoT Edge'}).DisplayVersion 30 | if ([string]::IsNullOrEmpty($eflowVersion)) 31 | { 32 | Write-Host "Error - EFLOW it's no installed in the Windows host OS" -ForegroundColor "Red" 33 | return 34 | } 35 | elseif([int]$eflowVersion.Split(".")[1] -eq 2 -and [int]$eflowVersion.Split(".")[2] -lt 10) 36 | { 37 | Write-Host "Error - EFLOW version $eflowVersion it's not supported" -ForegroundColor "Red" 38 | return 39 | } 40 | elseif([int]$eflowVersion.Split(".")[1] -eq 1 -and [int]$eflowVersion.Split(".")[2] -lt 2207) 41 | { 42 | Write-Host "Error - EFLOW version $eflowVersion it's not supported" -ForegroundColor "Red" 43 | return 44 | } 45 | 46 | usbipd list 47 | 48 | } 49 | catch [Exception] 50 | { 51 | # An exception was thrown, write it out and exit 52 | Write-Host "Exception caught" -ForegroundColor "Red" 53 | Write-Host $_.Exception.Message.ToString() -ForegroundColor "Red" 54 | return 55 | } 56 | } -------------------------------------------------------------------------------- /eflow-util/eflow-usbip/README.md: -------------------------------------------------------------------------------- 1 | # EFLOW Util PowerShell functions 2 | 3 | Understand EFLOW-Util PowerShell functions that provide extra mechanisms to connect and disconnect USB devices to the EFLOW VM. 4 | 5 | ### :warning: Important 6 | _The following functions are sample codes that are not meant to be used in production deployments. For production use, ensure you validate the functionality and create your own functions based on these samples. Furthermore, functions are subject to change and deletion._ 7 | 8 | ## Get-EflowUSBDevices 9 | 10 | The [**Get-EflowUSBDevices**](./Get-EflowUSBDevices.ps1) lists all of the USB devices connected to Windows that could be attached to the EFLOW virtual machine. 11 | This command takes no parameters. It prints out a table that contains four properties: 12 | 13 | - BUSID 14 | - VID:PID 15 | - Device 16 | - State 17 | 18 | ## Add-EflowUSBDevices 19 | 20 | The [**Add-EflowUSBDevices**](./Add-EflowUSBDevices.ps1) command connects the USB device to the EFLOW virtual machine 21 | 22 | | Parameter | Accepted values | Comments | 23 | | --------- | --------------- | -------- | 24 | | busId | String | Bus-id assigned by Windows to the USB device. | 25 | | hostIp | String IP4Address | IP address of the Windows host OS | 26 | 27 | ## Remove-EflowUSBDevices 28 | 29 | The [**Remove-EflowUSBDevices**](./Remove-EflowUSBDevices.ps1) command disconnects the USB device to the EFLOW virtual machine 30 | 31 | | Parameter | Accepted values | Comments | 32 | | --------- | --------------- | -------- | 33 | | busId | String | Bus-id assigned by Windows to the USB device. | 34 | | hostIp | String IP4Address | IP address of the Windows host OS | 35 | -------------------------------------------------------------------------------- /eflow-util/eflow-usbip/Remove-EflowUSBDevices.ps1: -------------------------------------------------------------------------------- 1 |  function Remove-EflowUSBDevices 2 | { 3 | <# 4 | .DESCRIPTION 5 | Disconnects the USB device with to the EFLOW virutal machine 6 | 7 | .PARAMETER busid 8 | Bus-id assigned by Windows to the USB device 9 | 10 | .PARAMETER hostIp 11 | IP address of the Windows host OS 12 | #> 13 | 14 | param ( 15 | 16 | [Parameter(Mandatory)] 17 | [String] $busId, 18 | 19 | [Parameter(Mandatory)] 20 | [String] $hostIp 21 | ) 22 | 23 | try 24 | { 25 | if (-not ($hostIp -as [IPAddress] -as [Bool])) { 26 | Write-Host "Error: Invalid IP4Address $hostIp" -ForegroundColor Red 27 | return 28 | } 29 | 30 | $usbipd = Get-ChildItem -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' | Get-ItemProperty | Where-Object {$_.DisplayName -eq 'usbipd-win'} 31 | if($usbipd) 32 | { 33 | Write-Host "Ok - USBIP-Win is installed on the Windows host OS" 34 | if ( [bool](Get-Command -Name 'usbipd' -ErrorAction SilentlyContinue)) 35 | { 36 | Write-Host "Ok - USBIP-Win is loaded" 37 | } 38 | else 39 | { 40 | Write-Host "Error - USBIP-Win is not loaded - Reopen the PowerShell session or manually import the command tool" -ForegroundColor "Red" 41 | } 42 | } 43 | else 44 | { 45 | Write-Host "Error - USBIP-Win it's not installed" -ForegroundColor "Red" 46 | return 47 | } 48 | 49 | [String]$eflowVersion = (Get-ChildItem -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' | Get-ItemProperty | Where-Object {$_.DisplayName -eq 'Azure IoT Edge LTS' -or $_.DisplayName -eq 'Azure IoT Edge'}).DisplayVersion 50 | if ([string]::IsNullOrEmpty($eflowVersion)) 51 | { 52 | Write-Host "Error - EFLOW it's no installed in the Windows host OS" -ForegroundColor "Red" 53 | return 54 | } 55 | elseif([int]$eflowVersion.Split(".")[1] -eq 2 -and [int]$eflowVersion.Split(".")[2] -lt 10) 56 | { 57 | Write-Host "Error - EFLOW version $eflowVersion it's not supported" -ForegroundColor "Red" 58 | return 59 | } 60 | elseif([int]$eflowVersion.Split(".")[1] -eq 1 -and [int]$eflowVersion.Split(".")[2] -lt 2207) 61 | { 62 | Write-Host "Error - EFLOW version $eflowVersion it's not supported" -ForegroundColor "Red" 63 | return 64 | } 65 | 66 | Write-Host "Detaching the USB device inside the EFLOW VM" 67 | 68 | $portCommand = "sudo usbip port | grep $hostIp" + ":3240/$busId -B 2" 69 | $portResult = Invoke-EflowVmCommand "$portCommand" 70 | $regexMatch = [regex]::match($portResult, "Port\s*(\d*)") 71 | 72 | if($regexMatch.Success) 73 | { 74 | $port = $regexMatch.Groups[1].Value 75 | Write-Host "Ok - Device with busId=$busId attached to port=$port" 76 | Invoke-EflowVmCommand "sudo usbip detach -p $port" 77 | } 78 | else 79 | { 80 | Write-Host "Error - Couldn't find a device with the busId=$busId" -ForegroundColor "Red" 81 | return 82 | } 83 | 84 | Write-Host "Stopping sharing the USB device to the EFLOW VM" 85 | usbipd unbind --busid=$busId 86 | 87 | } 88 | catch [Exception] 89 | { 90 | # An exception was thrown, write it out and exit 91 | Write-Host "Exception caught" -ForegroundColor "Red" 92 | Write-Host $_.Exception.Message.ToString() -ForegroundColor "Red" 93 | return 94 | } 95 | } -------------------------------------------------------------------------------- /eflow-util/firewall-rules/EflowUtil-FirewallRules.psm1: -------------------------------------------------------------------------------- 1 | <# 2 | Root Module including all the required modules 3 | #> 4 | 5 | # Check for admin privilege first before proceeding... 6 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` 7 | [Security.Principal.WindowsBuiltInRole]::Administrator)) { 8 | Write-Host "Ensure to tun this PowerShell module in Administrator mode!" -ForegroundColor "Red" 9 | return 10 | } 11 | 12 | # If admin privilege, import EFLOW module 13 | Import-Module AzureEflow 14 | 15 | # Source all the powershell scripts for the functions 16 | . $PSScriptRoot\Get-FirewallRules.ps1 17 | . $PSScriptRoot\Set-FirewallRules.ps1 -------------------------------------------------------------------------------- /eflow-util/firewall-rules/Get-FirewallRules.ps1: -------------------------------------------------------------------------------- 1 | function Get-EflowVmFirewallRules 2 | { 3 | <# 4 | .DESCRIPTION 5 | Iptables is used to set up, maintain, and inspect the tables of IP packet filter rules in the Linux kernel. For more information, check https://linux.die.net/man/8/iptables 6 | 7 | .PARAMETER table 8 | Name of table - Each table contains a number of built-in chains and may also contain user-defined chains. 9 | 10 | .PARAMETER chain 11 | Name of chain - Each chain is a list of rules which can match a set of packets. 12 | 13 | .PARAMETER protocol 14 | Name of network protocol (UDP/TCP/ICMP). 15 | 16 | .PARAMETER port 17 | Port number inside CBL-Mariner 18 | 19 | .PARAMETER state 20 | Network connection states to match 21 | 22 | .PARAMETER jump 23 | This specifies the target of the rule; i.e., what to do if the packet matches it. 24 | 25 | .PARAMETER customRule 26 | If a more complex rule is needed, this parameter cna be used to input the rule string 27 | 28 | #> 29 | 30 | param ( 31 | 32 | [Parameter(Mandatory)] 33 | [ValidateSet("INPUT", "OUTPUT", "FORWARD", "DOCKER", "DOCKER-ISOLATION-STAGE-1", "DOCKER-ISOLATION-STAGE-2", "DOCKER-USER")] 34 | [String] $chain, 35 | 36 | [ValidateSet("udp", "tcp", "icmp", "all")] 37 | [Parameter(Mandatory)] 38 | [String] $protocol, 39 | 40 | [ValidateRange(1,65535)] 41 | [Parameter(Mandatory)] 42 | [int] $port, 43 | 44 | [ValidateSet("REJECT", "ACCEPT", "DROP")] 45 | [Parameter(Mandatory)] 46 | [String] $jump, 47 | 48 | [ValidateSet("filter", "nat", "mangle", "raw")] 49 | [String] $table, 50 | 51 | [ValidateSet("INVALID", "ESTABLISHED", "NEW", "RELATED", "SNAT", "DNAT")] 52 | [String] $state, 53 | 54 | [String] $customRule 55 | ) 56 | 57 | try 58 | { 59 | [String]$vmCommand = ""; 60 | 61 | if (![string]::IsNullOrEmpty($customRule)) 62 | { 63 | $vmCommand = $customRule 64 | } 65 | else 66 | { 67 | $vmCommand = "sudo iptables"; 68 | 69 | if (![string]::IsNullOrEmpty($table)) 70 | { 71 | $vmCommand += " --table $($table)" 72 | } 73 | 74 | $vmCommand += "-A $($chain) -p $($protocol) --dport $($port) -j $($jump)" 75 | 76 | if (![string]::IsNullOrEmpty($state)) 77 | { 78 | $vmCommand += " --state $($state)" 79 | } 80 | } 81 | 82 | $result = Invoke-EflowVmCommand -command $vmCommand -ignoreError 83 | 84 | if([string]::IsNullOrEmpty($result)) 85 | { 86 | Write-Host "Rule not found" 87 | } 88 | else 89 | { 90 | $result 91 | } 92 | } 93 | catch [Exception] 94 | { 95 | # An exception was thrown, write it out and exit 96 | Write-Host "Exception caught!!!" -ForegroundColor "Red" 97 | Write-Host $_.Exception.Message.ToString() -ForegroundColor "Red" 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /eflow-util/firewall-rules/README.md: -------------------------------------------------------------------------------- 1 | # EFLOW Util Firewall Rules functions 2 | 3 | Understand EFLOW-Util FirewallRules PowerShell functions that provide extra mechanisms to get and set firewall rules of EFLOW VM. 4 | 5 | ### :warning: Important 6 | _The following functions are samples codes that are not meant to be used in production deployments. Furthermore, functions are subject to change and deletion. Make sure you create your own functions based on these samples._. 7 | 8 | ## Get-EflowVmFirewallRules 9 | 10 | The [**Get-EflowVmFirewallRules**](./Get-FirewallRules.ps1) command checks the CBL-Mariner firewall rules. 11 | The command returns the list of all firewall rules configured. Use the optional parameters to define a table or chain. 12 | 13 | The EFLOW VM uses CBL-Mariner, which includes an iptables based firewall. For more information about iptables, visit [iptables page](https://linux.die.net/man/8/iptables). 14 | 15 | | Parameter | Accepted values | Comments | 16 | | --------- | --------------- | -------- | 17 | | _table_ | filter, nat, mangle, raw | Name of the table - Each table contains several built-in chains and may also contain user-defined chains. | 18 | | _chain_ | INPUT, OUTPUT, FORWARD, DOCKER, DOCKER-ISOLATION-STAGE-1, DOCKER-ISOLATION-STAGE-2, DOCKER-USER | Name of chain - Each chain is a list of rules which can match a set of packets. | 19 | 20 | ## Set-EflowVmFirewallRules 21 | 22 | The [**Set-EflowVmFirewallRules**](./Set-FirewallRules.ps1) command adds the specified rule to CBL-Mariner firewall. 23 | Use the optional parameters to define a custom rule. For a more specific rule, use the _customRule_ parameter. 24 | 25 | The EFLOW VM uses CBL-Mariner, which includes an iptables based firewall. For more information about iptables, visit [iptables page](https://linux.die.net/man/8/iptables). 26 | 27 | | Parameter | Accepted values | Comments | 28 | | --------- | --------------- | -------- | 29 | | _table_ | filter, nat, mangle, raw | Name of the table - Each table contains several built-in chains and may also contain user-defined chains. | 30 | | _chain_ | INPUT, OUTPUT, FORWARD, DOCKER, DOCKER-ISOLATION-STAGE-1, DOCKER-ISOLATION-STAGE-2, DOCKER-USER | Name of chain - Each chain is a list of rules which can match a set of packets. | 31 | | _protocol_ | udp, tcp, icmp, all | Name of network protocol. | 32 | | _port_ | Integer value (0, 65535) | Port number inside CBL-Mariner. | 33 | | _state_ | INVALID, ESTABLISHED, NEW, RELATED, SNAT, DNAT | Network connection states to match. | 34 | | _jump_ | REJECT, ACCEPT, DROP | Network connection states to match. | 35 | | _unset_ | - | If this parameter is present, the provided rule will be unset/deleted. | 36 | | _customRule_ | String | If a more complex rule is needed, this parameter can be used to input the rule string. | 37 | -------------------------------------------------------------------------------- /eflow-util/firewall-rules/Set-FirewallRules.ps1: -------------------------------------------------------------------------------- 1 | function Set-EflowVmFirewallRules 2 | { 3 | <# 4 | .DESCRIPTION 5 | Iptables is used to set up, maintain, and inspect the tables of IP packet filter rules in the Linux kernel. For more information, check https://linux.die.net/man/8/iptables 6 | 7 | .PARAMETER table 8 | Name of table - Each table contains a number of built-in chains and may also contain user-defined chains. 9 | 10 | .PARAMETER chain 11 | Name of chain - Each chain is a list of rules which can match a set of packets. 12 | 13 | .PARAMETER protocol 14 | Name of network protocol (UDP/TCP/ICMP). 15 | 16 | .PARAMETER port 17 | Port number inside CBL-Mariner 18 | 19 | .PARAMETER state 20 | Network connection states to match 21 | 22 | .PARAMETER jump 23 | This specifies the target of the rule; i.e., what to do if the packet matches it. 24 | 25 | .PARAMETER unset 26 | If unset is present, the rule be unset/deleted. 27 | 28 | .PARAMETER customRule 29 | If a more complex rule is needed, this parameter cna be used to input the rule string 30 | 31 | #> 32 | 33 | param ( 34 | 35 | [Parameter(Mandatory)] 36 | [ValidateSet("INPUT", "OUTPUT", "FORWARD", "DOCKER", "DOCKER-ISOLATION-STAGE-1", "DOCKER-ISOLATION-STAGE-2", "DOCKER-USER")] 37 | [String] $chain, 38 | 39 | [ValidateSet("udp", "tcp", "icmp", "all")] 40 | [Parameter(Mandatory)] 41 | [String] $protocol, 42 | 43 | [ValidateRange(1,65535)] 44 | [Parameter(Mandatory)] 45 | [int] $port, 46 | 47 | [ValidateSet("REJECT", "ACCEPT", "DROP")] 48 | [Parameter(Mandatory)] 49 | [String] $jump, 50 | 51 | [ValidateSet("filter", "nat", "mangle", "raw")] 52 | [String] $table, 53 | 54 | [ValidateSet("INVALID", "ESTABLISHED", "NEW", "RELATED", "SNAT", "DNAT")] 55 | [String] $state, 56 | 57 | [Switch] $unset, 58 | 59 | [String] $customRule 60 | ) 61 | 62 | try 63 | { 64 | [String]$vmCommand = ""; 65 | 66 | if (![string]::IsNullOrEmpty($customRule)) 67 | { 68 | $vmCommand = $customRule 69 | } 70 | else 71 | { 72 | if($unset.IsPresent) 73 | { 74 | $vmCommand = "sudo iptables -D " 75 | } 76 | else 77 | { 78 | $vmCommand = "sudo iptables -A " 79 | } 80 | 81 | if (![string]::IsNullOrEmpty($table)) 82 | { 83 | $vmCommand += " --table $($table)" 84 | } 85 | 86 | $vmCommand += "-A $($chain) -p $($protocol) --dport $($port) -j $($jump)" 87 | 88 | if (![string]::IsNullOrEmpty($state)) 89 | { 90 | $vmCommand += " --state $($state)" 91 | } 92 | } 93 | 94 | $result = Invoke-EflowVmCommand -command $vmCommand -ignoreError 95 | 96 | if([string]::IsNullOrEmpty($result)) 97 | { 98 | Write-Host "Rule added" 99 | } 100 | else 101 | { 102 | $result 103 | } 104 | } 105 | catch [Exception] 106 | { 107 | # An exception was thrown, write it out and exit 108 | Write-Host "Exception caught!!!" -ForegroundColor "Red" 109 | Write-Host $_.Exception.Message.ToString() -ForegroundColor "Red" 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /eflow-util/updateWssdCert.ps1: -------------------------------------------------------------------------------- 1 | # Check for admin privilege first before proceeding... 2 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` 3 | [Security.Principal.WindowsBuiltInRole]::Administrator)) { 4 | Write-Host "Ensure to tun this PowerShell module in Administrator mode!" -ForegroundColor "Red" 5 | return 6 | } 7 | 8 | Write-Host "Stopping WSSDAgent service" 9 | Stop-Service wssdagent 10 | Remove-Item -Force -Path "HKLM:SOFTWARE\Microsoft\WssdAgent\v0.10.8-alpha.10\CertificateInternal" 11 | Remove-Item -Force -Path "HKLM:SOFTWARE\Microsoft\WssdAgent\v0.10.8-alpha.10\IdentityInternal" 12 | 13 | Write-Host "Restarting WSSDAgent service" 14 | Start-Service wssdagent 15 | Start-Sleep 10 16 | 17 | Remove-Item -Recurse -Force -Path "$env:UserProfile\.wssd\nodectl" 18 | 19 | & "$env:ProgramFiles\Azure IoT Edge\nodectl.exe" security login --loginpath "$env:Programdata\wssdagent\nodelogin.yaml" --identity 20 | Start-Sleep 15 21 | Copy-Item -Path "$env:UserProfile\.wssd\nodectl\cloudconfig"  -Destination "$env:Programdata\azure iot edge\protected\.wssd\cloudconfig" -Force 22 | 23 | Remove-Item -Recurse -Force -Path "$env:UserProfile\.wssd\nodectl" 24 | 25 | try 26 | { 27 | Invoke-EflowVmCommand "ls -la" 28 | Write-Host "Connection to EFLOW VM successful." 29 | } 30 | catch [Exception] 31 | { 32 | Write-Host "Error caught while invoking VM command" 33 | $e = $_.Exception 34 | Write-Host $e.Message.ToString() 35 | } -------------------------------------------------------------------------------- /eflowautodeploy/eflow-userconfig-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion":"1.1", 3 | "version":"1.0", 4 | "eflowProduct" : "Azure IoT Edge LTS", 5 | "eflowProductUrl" : "", 6 | "installOptions":{ 7 | "installPath":"", 8 | "vhdxPath":"" 9 | }, 10 | "enduser":{ 11 | "acceptEula" : "Yes", 12 | "acceptOptionalTelemetry" : "" 13 | }, 14 | "network":{ 15 | "adapterName": "Ethernet", 16 | "vswitchName" : "", 17 | "vswitchType" : "", 18 | "ip4Address": "", 19 | "ip4GatewayAddress": "", 20 | "ip4PrefixLength" : "", 21 | "useHostProxy" : false, 22 | "httpProxy":"", 23 | "httpsProxy":"", 24 | "ftpProxy" :"", 25 | "dnsServers":"" 26 | }, 27 | "vmConfig":{ 28 | "cpuCount" : 0, 29 | "memoryInMB" : 0, 30 | "vmDiskSize" : 0, 31 | "vmDataSize" : 0, 32 | "gpuPassthroughType" : "", 33 | "gpuName" : "", 34 | "gpuCount" : 0 35 | }, 36 | "vmFeature":{ 37 | "DpsTpm": false, 38 | "Defender": false 39 | }, 40 | "eflowProvisioning":{ 41 | "provisioningType" : "", 42 | "devConnString" : "", 43 | "iotHubHostname" : "", 44 | "deviceId" : "", 45 | "scopeId" : "", 46 | "symmKey": "", 47 | "registrationId" : "", 48 | "identityCertPath" : "", 49 | "identityPrivKeyPath" : "", 50 | "globalEndpoint" : "" 51 | } 52 | } -------------------------------------------------------------------------------- /eflowautodeploy/eflow-userconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion":"1.1", 3 | "version":"1.0", 4 | "eflowProduct" : "Azure IoT Edge LTS", 5 | "enduser":{ 6 | "acceptEula" : "Yes", 7 | "acceptOptionalTelemetry" : "Yes" 8 | } 9 | } -------------------------------------------------------------------------------- /eflowautodeploy/eflow-userconfig.puml: -------------------------------------------------------------------------------- 1 | @startjson eflowAutoDeploy 2 | 26 | #highlight "schemaVersion" 27 | { 28 | "schemaVersion":"1.1", 29 | "version":"1.0", 30 | "eflowProduct" :["Azure IoT Edge LTS", "Azure IoT Edge CR X64","Azure IoT Edge CR ARM64", "Azure IoT Edge 1.4 LTS X64", "Azure IoT Edge 1.4 LTS ARM64" ], 31 | "eflowProductUrl" : "URL", 32 | "installOptions":{ 33 | "installPath":"String", 34 | "vhdxPath":"String" 35 | }, 36 | "enduser":{ 37 | "acceptEula" : ["Yes","No"], 38 | "acceptOptionalTelemetry" : ["Yes","No"] 39 | }, 40 | "vmFeature":{ 41 | "DpsTpm": "Boolean", 42 | "Defender": "Boolean" 43 | }, 44 | "vmConfig":{ 45 | "cpuCount" : "1 or more", 46 | "memoryInMB" : "1024 or more", 47 | "vmDiskSize" : "[21-2000]", 48 | "vmDataSize" : "[2-2000]", 49 | "gpuPassthroughType" : ["DirectDeviceAssignment", "ParaVirtualization"], 50 | "gpuName" : "String", 51 | "gpuCount" : "0 or more" 52 | }, 53 | "network":{ 54 | "adapterName": "String", 55 | "vswitchName" : "String", 56 | "vswitchType" : ["External", "Internal"], 57 | "ip4Address": "IPAddress", 58 | "ip4GatewayAddress": "IPAddress", 59 | "ip4PrefixLength" : "24", 60 | "useHostProxy" : "Boolean", 61 | "httpProxy":"URL", 62 | "httpsProxy":"URL", 63 | "ftpProxy":"URL", 64 | "dnsServers":"IPAddress[]" 65 | }, 66 | "eflowProvisioning":{ 67 | "provisioningType" : ["ManualConnectionString","ManualX509","DpsTPM","DpsX509","DpsSymmetricKey"], 68 | "devConnString" : "String", 69 | "iotHubHostname" : "String", 70 | "deviceId" : "String", 71 | "scopeId" : "String", 72 | "symmKey": "String", 73 | "registrationId" : "String", 74 | "identityCertPath" : "String", 75 | "identityPrivKeyPath" : "String", 76 | "globalEndpoint" : "String" 77 | } 78 | } 79 | @endjson -------------------------------------------------------------------------------- /eflowautodeploy/eflowAutoDeploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/eflowautodeploy/eflowAutoDeploy.png -------------------------------------------------------------------------------- /eflowremotedeploy/README.md: -------------------------------------------------------------------------------- 1 | # EFLOW Remote Deploy 2 | 3 | eflowRemoteDeploy enables you to deploy the Azure IoT Edge for Linux on Windows (EFLOW) using eflowAutoDeploy through Intune, Arc for Server channels. 4 | 5 | 6 | ## Via Intune 7 | 8 | 1. Update the `eflowRemoteDeploy.ps1` script with the required parameters in the `$jsonContent` Here string. 9 | 2. Deploy this script with the following the instructions available at [Use PowerShell scripts on Windows 10/11 devices in Intune](https://docs.microsoft.com/mem/intune/apps/intune-management-extension?msclkid=ed33bab9d07311eca7ecb4b9f790a046). 10 | 11 | ## Via Arc Enabled Servers - Custom Script Extenstion 12 | 13 | 1. Update the `eflowRemoteDeploy.ps1` script with the required parameters in the `$jsonContent` Here string. 14 | 2. Deploy this script with the following the instructions available at [Custom Script Extension for Windows](https://docs.microsoft.com/azure/virtual-machines/extensions/custom-script-windows). 15 | -------------------------------------------------------------------------------- /eflowremotedeploy/eflowRemoteDeploy.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Sample script to deploy eflow via Intune 3 | #> 4 | # Here string for the json content 5 | $jsonContent = @' 6 | { 7 | "schemaVersion":"1.0", 8 | "version":"1.0", 9 | "eflowProduct" : "Azure IoT Edge LTS", 10 | "enduser":{ 11 | "acceptEula" : "Yes", 12 | "acceptOptionalTelemetry" : "Yes" 13 | }, 14 | "eflowProvisioning":{ 15 | "provisioningType" : "ManualConnectionString", 16 | "devConnString" : "" 17 | } 18 | } 19 | '@ 20 | $exitCode = 0 21 | #Download the AutoDeploy script 22 | $deploytime = Get-Date -Format "yyMMdd-HHmm" 23 | $transcriptFile = "$PSScriptRoot\eadlog-$deploytime.txt" 24 | Start-Transcript -Path $transcriptFile 25 | 26 | Set-ExecutionPolicy Bypass -Scope Process -Force 27 | $scriptFile = "$PSScriptRoot\AutoDeploy.ps1" 28 | $jsonFile = "$PSScriptRoot\userconfig.json" 29 | Out-File -FilePath $jsonFile -InputObject $jsonContent -Force 30 | $url = 'https://raw.githubusercontent.com/Azure/iotedge-eflow/main/eflowautodeploy/eflowAutoDeploy.ps1' 31 | if (Test-Path $scriptFile) { 32 | Remove-Item $scriptFile -Force | Out-Null 33 | } 34 | $ProgressPreference = 'SilentlyContinue' 35 | Invoke-WebRequest $url -OutFile $scriptFile 36 | $ProgressPreference = 'Continue' 37 | # dot source the script 38 | . $scriptFile 39 | # invoke the workflow 40 | $retval = Start-EadWorkflow $jsonFile 41 | # report error via Write-Error for Intune to show proper status 42 | if ($retval) { 43 | Write-Host "Deployment Successful" 44 | } else { 45 | Write-Error -Message "Deployment failed" -Category OperationStopped 46 | $exitCode = -1 47 | } 48 | Stop-Transcript | Out-Null 49 | exit $exitCode -------------------------------------------------------------------------------- /samples/camera-over-rtsp/.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | 35 | .vs/ 36 | CameraRTPStreamerApp/build/x64/ 37 | NetworkMediaStreamerBase/build/x64/ 38 | RTPMediaStreamer/build/x64/ 39 | RTSPServer/build/x64/ 40 | x64/ -------------------------------------------------------------------------------- /samples/camera-over-rtsp/CameraRTPStreamerApp/build/CameraRTPStreamerApp.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /samples/camera-over-rtsp/CameraRTPStreamerApp/build/CameraRTPStreamerApp.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | prueba 5 | WindowsLocalDebugger 6 | 7 | 8 | 1 3 9 | WindowsLocalDebugger 10 | 11 | -------------------------------------------------------------------------------- /samples/camera-over-rtsp/CameraRTPStreamerApp/build/RTSPServer.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/camera-over-rtsp/CameraRTPStreamerApp/build/RTSPServer.log -------------------------------------------------------------------------------- /samples/camera-over-rtsp/Common/inc/NetworkMediaStreamer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for more information 3 | 4 | #pragma once 5 | 6 | /* Note: Application must include following files in this exact order before including this file 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | */ 14 | 15 | #if (defined VIDEOSTREAMER_EXPORTS) || (defined VideoStreamer_EXPORTS) 16 | #define VIDEOSTREAMER_API __declspec(dllexport) 17 | #else 18 | #define VIDEOSTREAMER_API __declspec(dllimport) 19 | #endif 20 | 21 | namespace ABI 22 | { 23 | using namespace ABI::Windows::Foundation; 24 | using namespace ABI::Windows::Storage::Streams; 25 | template<> MIDL_INTERFACE("7E37DD5F-7749-46E4-856A-FE098BAA142D") IEventHandler : IEventHandler_impl{}; 26 | typedef IEventHandler PacketHandler; 27 | } 28 | 29 | namespace winrt 30 | { 31 | typedef winrt::Windows::Foundation::EventHandler PacketHandler; 32 | template <> struct winrt::impl::guid_storage 33 | { 34 | static constexpr guid value{ __uuidof(ABI::PacketHandler) }; 35 | }; 36 | } 37 | 38 | //EXTERN_C const IID IID_IVideoStreamer; 39 | MIDL_INTERFACE("022C6CB9-64D5-472F-8753-76382CC5F4DA") 40 | INetworkMediaStreamSink : public IMFStreamSink 41 | { 42 | public: 43 | virtual STDMETHODIMP AddTransportHandler(ABI::PacketHandler * pPackethandler, LPCWSTR pProtocol = L"rtp", LPCWSTR pParam = L"") = 0; 44 | virtual STDMETHODIMP RemoveTransportHandler(ABI::PacketHandler* pPacketHandler) = 0; 45 | virtual STDMETHODIMP AddNetworkClient(LPCWSTR pDestination, LPCWSTR pProtocol = L"rtp", LPCWSTR pParams = L"") = 0; 46 | virtual STDMETHODIMP RemoveNetworkClient(LPCWSTR pDestination) = 0; 47 | virtual STDMETHODIMP GenerateSDP(uint8_t* pBuf, size_t maxSize, LPCWSTR pDestination) = 0; 48 | virtual STDMETHODIMP Start(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) = 0; 49 | virtual STDMETHODIMP Stop(MFTIME hnsSystemTime) = 0; 50 | virtual STDMETHODIMP Pause(MFTIME hnsSystemTime) = 0; 51 | virtual STDMETHODIMP Shutdown() = 0; 52 | 53 | }; 54 | -------------------------------------------------------------------------------- /samples/camera-over-rtsp/Common/inc/RTPMediaStreamer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for more information 3 | 4 | #pragma once 5 | 6 | /* Must include following before this file 7 | #include "NetworkMediaStreamer.h" 8 | */ 9 | 10 | #if (defined RTPMEDIASTREAMER_EXPORTS) 11 | #define RTPMEDIASTREAMER_API __declspec(dllexport) 12 | #else 13 | #define RTPMEDIASTREAMER_API __declspec(dllimport) 14 | #endif 15 | 16 | RTPMEDIASTREAMER_API STDMETHODIMP CreateRTPMediaSink(IMFMediaType** apMediaTypes, DWORD dwMediaTypeCount, IMFMediaSink** ppMediaSink); -------------------------------------------------------------------------------- /samples/camera-over-rtsp/NetworkMediaStreamerBase/build/NetworkMediaStreamer.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | Header Files 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | -------------------------------------------------------------------------------- /samples/camera-over-rtsp/NetworkMediaStreamerBase/inc/NwMediaStreamSinkBase.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for more information 3 | 4 | #pragma once 5 | 6 | #define RETURN_IF_SHUTDOWN if(m_bIsShutdown) return MF_E_SHUTDOWN; 7 | #define RETURN_IF_NULL(p) if(!p) return E_POINTER; 8 | #define HRESULT_EXCEPTION_BOUNDARY_FUNC catch(...) { auto hr = winrt::to_hresult(); return hr;} 9 | 10 | class NwMediaStreamSinkBase : public winrt::implements 11 | { 12 | protected: 13 | uint8_t* m_pVideoHeader; 14 | uint32_t m_VideoHeaderSize; 15 | bool m_bIsShutdown; 16 | winrt::weak_ref m_spParentSink; 17 | winrt::com_ptr m_spEventQueue; 18 | winrt::com_ptr m_spMTHandler; 19 | DWORD m_dwStreamID; 20 | NwMediaStreamSinkBase(IMFMediaType* pMediaType, IMFMediaSink* pParent, DWORD dwStreamID); 21 | 22 | virtual ~NwMediaStreamSinkBase(); 23 | 24 | virtual STDMETHODIMP PacketizeAndSend(IMFSample* pSample) = 0; 25 | 26 | public: 27 | 28 | // INetworkStreamSink 29 | STDMETHODIMP Start(MFTIME hnsSystemTime, LONGLONG llClockStartOffset); 30 | STDMETHODIMP Stop(MFTIME hnsSystemTime); 31 | STDMETHODIMP Pause(MFTIME hnsSystemTime); 32 | STDMETHODIMP Shutdown(); 33 | 34 | // IMFMediaEventGenerator 35 | STDMETHODIMP BeginGetEvent(IMFAsyncCallback* pCallback, IUnknown* pState); 36 | 37 | STDMETHODIMP EndGetEvent(IMFAsyncResult* pResult, IMFMediaEvent** ppEvent); 38 | 39 | STDMETHODIMP GetEvent(DWORD dwFlags, IMFMediaEvent** ppEvent); 40 | 41 | STDMETHODIMP QueueEvent( 42 | MediaEventType met, REFGUID extendedType, 43 | HRESULT hrStatus, const PROPVARIANT* pvValue); 44 | 45 | // IMFStreamSink 46 | STDMETHODIMP GetMediaSink(IMFMediaSink** ppMediaSink); 47 | 48 | STDMETHODIMP GetIdentifier(DWORD* pdwIdentifier); 49 | 50 | STDMETHODIMP GetMediaTypeHandler(IMFMediaTypeHandler** ppHandler); 51 | 52 | STDMETHODIMP ProcessSample(IMFSample* pSample); 53 | 54 | STDMETHODIMP PlaceMarker( 55 | MFSTREAMSINK_MARKER_TYPE eMarkerType, 56 | const PROPVARIANT* pvarMarkerValue, 57 | const PROPVARIANT* pvarContextValue); 58 | 59 | STDMETHODIMP Flush(void); 60 | 61 | }; 62 | 63 | -------------------------------------------------------------------------------- /samples/camera-over-rtsp/NetworkMediaStreamerBase/inc/pch.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for more information 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "NetworkMediaStreamer.h" 19 | #include "NwMediaStreamSinkBase.h" -------------------------------------------------------------------------------- /samples/camera-over-rtsp/RTPMediaStreamer/build/RTPMediaStreamer.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {8e11ae21-f6ae-43ea-ab19-0a590ce819f1} 6 | 7 | 8 | {471d69f4-a133-4c08-9d8e-5647e1a77a68} 9 | 10 | 11 | 12 | 13 | Header Files 14 | 15 | 16 | Header Files 17 | 18 | 19 | Header Files 20 | 21 | 22 | 23 | 24 | Source Files 25 | 26 | 27 | Source Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /samples/camera-over-rtsp/RTPMediaStreamer/build/RTPMediaStreamer.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WindowsLocalDebugger 5 | 6 | -------------------------------------------------------------------------------- /samples/camera-over-rtsp/RTPMediaStreamer/inc/RTPStreamSink.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for more information 3 | 4 | #pragma once 5 | 6 | constexpr BYTE h264payloadType = 96; 7 | constexpr size_t rtpHeaderSize = 12; 8 | constexpr size_t stapAtypeHeaderSize = 1; 9 | constexpr size_t stapASzHeaderSize = 2; 10 | class TxContext final 11 | { 12 | uint16_t m_localRTPPort, m_localRTCPPort, m_remotePort; 13 | sockaddr_in m_remoteAddr; 14 | SOCKET m_rtpSocket, m_rtcpSocket; 15 | winrt::PacketHandler m_packetHandler; 16 | 17 | public: 18 | TxContext(std::string destination, winrt::PacketHandler packetHandler = nullptr); 19 | ~TxContext(); 20 | void SendPacket(winrt::Windows::Storage::Streams::IBuffer buf); 21 | 22 | uint32_t m_ssrc; 23 | uint64_t m_u64StartTime; 24 | uint32_t m_uSequenceNumber; 25 | }; 26 | 27 | class RTPVideoStreamSink final : public NwMediaStreamSinkBase 28 | { 29 | std::mutex m_guardlock; 30 | std::map> m_rtpStreamers; 31 | winrt::Windows::Storage::Streams::Buffer m_pTxBuf; 32 | size_t m_mtuSize; 33 | uint32_t m_packetizationMode; 34 | uint32_t m_uSequenceNumber; 35 | RTPVideoStreamSink(IMFMediaType* pMT, IMFMediaSink* pParent, DWORD dwStreamID); 36 | virtual ~RTPVideoStreamSink() = default; 37 | BYTE* FindSC(BYTE* bufStart, BYTE* bufEnd); 38 | STDMETHODIMP PacketizeAndSend(IMFSample* pSample) noexcept; 39 | void PacketizeMode0(BYTE* bufIn, size_t szIn, LONGLONG llSampleTime); 40 | 41 | void SendPacket(winrt::Windows::Storage::Streams::IBuffer buf, LONGLONG ts, bool bLastNalOfFrame); 42 | void PacketizeMode1(BYTE* bufIn, size_t szIn, LONGLONG llSampleTime); 43 | public: 44 | static INetworkMediaStreamSink* CreateInstance(IMFMediaType* pMediaType, IMFMediaSink* pParent, DWORD dwStreamID); 45 | 46 | STDMETHODIMP AddTransportHandler(ABI::PacketHandler* packetHandler, LPCWSTR protocol = L"rtp", LPCWSTR params = L"") override; 47 | STDMETHODIMP AddNetworkClient(LPCWSTR destination, LPCWSTR protocol = L"rtp", LPCWSTR param = L"") override; 48 | STDMETHODIMP RemoveNetworkClient(LPCWSTR destination) override; 49 | STDMETHODIMP RemoveTransportHandler(ABI::PacketHandler* packetHandler) override; 50 | STDMETHODIMP GenerateSDP(uint8_t* buf, size_t maxSize, LPCWSTR dest) override; 51 | 52 | }; 53 | 54 | -------------------------------------------------------------------------------- /samples/camera-over-rtsp/RTPMediaStreamer/inc/pch.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for more information 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "NetworkMediaStreamer.h" 16 | #include "NwMediaStreamSinkBase.h" 17 | #include "RTPMediaStreamer.h" 18 | #include "RTPStreamSink.h" -------------------------------------------------------------------------------- /samples/camera-over-rtsp/RTSPServer/build/RTSPServer.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {8e11ae21-f6ae-43ea-ab19-0a590ce819f1} 6 | 7 | 8 | {471d69f4-a133-4c08-9d8e-5647e1a77a68} 9 | 10 | 11 | 12 | 13 | Source Files 14 | 15 | 16 | Source Files 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | -------------------------------------------------------------------------------- /samples/camera-over-rtsp/RTSPServer/inc/RTSPServer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for more information 3 | 4 | #pragma once 5 | #define DBGLEVEL 1 6 | 7 | class RTSPServer : public winrt::implements 8 | { 9 | public: 10 | RTSPServer(ABI::RTSPSuffixSinkMap* streamers, uint16_t socketPort, IRTSPAuthProvider* pAuthProvider, PCCERT_CONTEXT* serverCerts, size_t uCertCount) 11 | : m_acceptEvent(nullptr) 12 | , m_callbackHandle(nullptr) 13 | , m_socketPort(socketPort) 14 | , m_bSecure(uCertCount) 15 | , m_masterSocket(INVALID_SOCKET) 16 | , m_bIsShutdown(false) 17 | { 18 | winrt::copy_from_abi(m_streamers, streamers); 19 | uCertCount&& winrt::check_pointer(serverCerts); 20 | m_serverCerts = winrt::com_array((uint32_t)uCertCount); 21 | for (uint32_t i = 0; i < uCertCount; i++) 22 | { 23 | winrt::check_pointer(serverCerts[i]); 24 | m_serverCerts[i] = CertDuplicateCertificateContext(serverCerts[i]); 25 | } 26 | m_spAuthProvider.copy_from(pAuthProvider); 27 | } 28 | 29 | virtual ~RTSPServer() 30 | { 31 | StopServer(); 32 | } 33 | 34 | // IRTSPServerControl 35 | STDMETHODIMP AddLogHandler(LoggerType type, ABI::LogHandler* handler, EventRegistrationToken* pToken) override try 36 | { 37 | winrt::check_pointer(pToken); 38 | winrt::check_pointer(handler); 39 | winrt::LogHandler h; 40 | winrt::copy_from_abi(h, handler); 41 | auto token = m_loggerEvents[(int)type].add(h); 42 | winrt::copy_to_abi(token, *pToken); 43 | return S_OK; 44 | }HRESULT_EXCEPTION_BOUNDARY_FUNC 45 | 46 | STDMETHODIMP RemoveLogHandler(LoggerType type, EventRegistrationToken token) override try 47 | { 48 | winrt::event_token tk; 49 | winrt::copy_from_abi(tk, token); 50 | m_loggerEvents[(int)type].remove(tk); 51 | return S_OK; 52 | }HRESULT_EXCEPTION_BOUNDARY_FUNC 53 | 54 | STDMETHODIMP AddSessionStatusHandler(LoggerType type, ABI::SessionStatusHandler* handler, EventRegistrationToken* pToken) override try 55 | { 56 | winrt::SessionStatusHandler h; 57 | winrt::copy_from_abi(h, handler); 58 | auto token = m_sessionStatusEvents.add(h); 59 | winrt::copy_to_abi(token, *pToken); 60 | return S_OK; 61 | }HRESULT_EXCEPTION_BOUNDARY_FUNC 62 | 63 | STDMETHODIMP RemoveSessionStatusHandler(LoggerType type, EventRegistrationToken token) override try 64 | { 65 | winrt::event_token tk; 66 | winrt::copy_from_abi(tk, token); 67 | m_sessionStatusEvents.remove(tk); 68 | return S_OK; 69 | }HRESULT_EXCEPTION_BOUNDARY_FUNC 70 | 71 | STDMETHODIMP StartServer() override; 72 | STDMETHODIMP StopServer() override; 73 | 74 | private: 75 | 76 | winrt::RTSPSuffixSinkMap m_streamers; 77 | 78 | std::map> m_rtspSessions; 79 | SOCKET m_masterSocket; // our masterSocket(socket that listens for RTSP client connections) 80 | winrt::handle m_acceptEvent; 81 | winrt::handle m_callbackHandle; 82 | uint16_t m_socketPort; 83 | bool m_bSecure; 84 | winrt::com_array m_serverCerts; 85 | winrt::event m_loggerEvents[(size_t)LoggerType::LOGGER_MAX]; 86 | winrt::event m_sessionStatusEvents; 87 | winrt::com_ptr m_spClock; 88 | bool m_bIsShutdown; 89 | std::mutex m_apiGuard; 90 | winrt::com_ptr m_spAuthProvider; 91 | }; 92 | -------------------------------------------------------------------------------- /samples/camera-over-rtsp/RTSPServer/inc/RtspSession.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for more information 3 | 4 | #pragma once 5 | 6 | #define RTP_DEFAULT_PORT 54554 7 | #define RTSP_BUFFER_SIZE 10000 // for incoming requests, and outgoing responses 8 | #define RTSP_PARAM_STRING_MAX 200 9 | 10 | // supported command types 11 | enum class RTSP_CMD 12 | { 13 | UNKNOWN = 0, 14 | OPTIONS, 15 | DESCRIBE, 16 | SETUP, 17 | PLAY, 18 | TEARDOWN 19 | }; 20 | 21 | class RTSPSession 22 | { 23 | public: 24 | RTSPSession( 25 | CSocketWrapper* rtspClientSocket, 26 | winrt::Windows::Foundation::Collections::PropertySet streamers, 27 | IRTSPAuthProvider* pAuthProvider, 28 | winrt::event* m_pLoggers); 29 | virtual ~RTSPSession(); 30 | 31 | virtual RTSP_CMD HandleRequest(char const* aRequest, unsigned aRequestSize); 32 | int GetStreamID(); 33 | SOCKET GetSocket() 34 | { 35 | return m_pRtspClient->GetSocket(); 36 | } 37 | 38 | void BeginSession(winrt::delegate completed); 39 | private: 40 | void Init(); 41 | void InitUDPTransport(); 42 | void InitTCPTransport(); 43 | RTSP_CMD ParseRequest(char const* aRequest, unsigned aRequestSize); 44 | char const* DateHeader(); 45 | std::string m_dest; 46 | // RTSP request command handlers 47 | void HandleCmdOPTIONS(); 48 | void HandleCmdDESCRIBE(); 49 | void HandleCmdSETUP(); 50 | void HandleCmdPLAY(); 51 | void HandleCmdTEARDOWN(); 52 | void Handle_RtspPAUSE(); 53 | void StopIfStreaming(); 54 | void SendToClient(std::string Response); 55 | 56 | uint32_t m_rtspSessionID; 57 | winrt::delegate m_sessionCompleted; 58 | std::unique_ptr m_pRtspClient; 59 | std::string m_rtspClientAddr; 60 | u_short m_rtspPort; 61 | u_short m_localRTPPort; // client port for UDP based RTP transport 62 | u_short m_localRTCPPort; // client port for UDP based RTCP transport 63 | 64 | u_short m_clientRTPPort; // client port for UDP based RTP transport 65 | u_short m_clientRTCPPort; // client port for UDP based RTCP transport 66 | bool m_bTcpTransport; // if Tcp based streaming was activated 67 | uint32_t m_ssrc; 68 | winrt::Windows::Foundation::Collections::PropertySet m_streamers; 69 | winrt::com_ptr m_spCurrentStreamer; 70 | 71 | // parameters of the last received RTSP request 72 | std::string m_strCSeq; // RTSP command sequence number 73 | std::string m_urlHostPort; // host:port part of the URL 74 | std::string m_urlProto; 75 | std::string m_curAuthSessionMsg; 76 | winrt::com_ptr m_spAuthProvider; 77 | winrt::handle m_rtspReadEvent; 78 | winrt::handle m_callBackHandle; 79 | winrt::PacketHandler m_packetHandler; 80 | bool m_bStreamingStarted, m_bTerminate, m_bAuthorizationReceived; 81 | std::unique_ptr m_pTcpTxBuff; 82 | std::unique_ptr m_pTcpRxBuff; 83 | std::string m_urlSuffix; 84 | std::mutex m_readDelegateMutex; 85 | winrt::event* m_pLoggerEvents; 86 | }; 87 | -------------------------------------------------------------------------------- /samples/camera-over-rtsp/RTSPServer/inc/SocketWrapper.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for more information 3 | 4 | #pragma once 5 | 6 | constexpr LPWSTR g_lpPackageName = (LPWSTR)UNISP_NAME; 7 | 8 | #define SEC_SUCCESS(Status) ((Status) >= 0) 9 | 10 | class CSocketWrapper 11 | { 12 | public: 13 | 14 | CSocketWrapper(SOCKET connectedSocket, winrt::array_view aCertContext = winrt::com_array()); 15 | virtual ~CSocketWrapper(); 16 | int Recv(BYTE* buf, int sz); 17 | int Send(BYTE* buf, int sz); 18 | 19 | SOCKET GetSocket() 20 | { 21 | return m_socket; 22 | } 23 | 24 | bool IsClientCertAuthenticated() 25 | { 26 | return m_bIsAuthenticated; 27 | } 28 | 29 | bool IsSecure() 30 | { 31 | return m_bIsSecure; 32 | } 33 | 34 | std::wstring GetClientCertUserName() 35 | { 36 | return m_clientUserName; 37 | } 38 | 39 | private: 40 | 41 | static void ReadDelegate(PVOID arg, BOOLEAN flag); 42 | void InitializeSecurity(); 43 | bool AuthenticateClient(); 44 | bool m_bIsSecure; 45 | SOCKET m_socket; 46 | bool m_bIsAuthenticated; 47 | 48 | CredHandle m_hCred; 49 | struct _SecHandle m_hCtxt; 50 | SECURITY_STATUS m_securityStatus; 51 | std::unique_ptr m_pInBuf; 52 | std::unique_ptr m_pOutBuf; 53 | DWORD m_bufSz; 54 | winrt::array_view m_aCertContext; 55 | SecPkgContext_StreamSizes m_secPkgContextStrmSizes; 56 | winrt::handle m_readEvent; 57 | std::condition_variable m_handshakeDone; 58 | winrt::handle m_callBackHandle; 59 | std::wstring m_clientUserName; 60 | }; -------------------------------------------------------------------------------- /samples/camera-over-rtsp/RTSPServer/inc/pch.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for more information 3 | 4 | #pragma once 5 | 6 | #define SECURITY_WIN32 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #define HRESULT_EXCEPTION_BOUNDARY_FUNC catch(...) { auto hr = winrt::to_hresult(); return hr;} 31 | #include "NetworkMediaStreamer.h" 32 | #include "RTSPServerControl.h" 33 | #include "SocketWrapper.h" 34 | #include "RtspSession.h" 35 | #include "RTSPServer.h" 36 | -------------------------------------------------------------------------------- /samples/camera-over-rtsp/docs/CameraAndResolution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/camera-over-rtsp/docs/CameraAndResolution.png -------------------------------------------------------------------------------- /samples/camera-over-rtsp/docs/RTSPVideoStreamer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/camera-over-rtsp/docs/RTSPVideoStreamer.jpg -------------------------------------------------------------------------------- /samples/camera-over-rtsp/docs/RTSPVideoStreamer.vsdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/camera-over-rtsp/docs/RTSPVideoStreamer.vsdx -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/simulator.md: -------------------------------------------------------------------------------- 1 | # Setting up Simulator on Windows 2 | 3 | 4 | 1. Setup Grafana on Windows 5 | 1. To install grafana on the Windows machine follow [this documentation](https://grafana.com/grafana/download/8.3.2?edition=oss&platform=windows) to download windows installer file and run it to install the application. 6 | 7 | > Note: Install Grafana version 8.3.2 with OSS Edition. 8 | 9 | 2. Open a **Command Prompt** as **Administrator**. 10 | 11 | 3. Install **AJAX Panel for Grafana** by running the below command 12 | 13 | ```powershell 14 | cd "C:\Program Files\GrafanaLabs\grafana\bin" 15 | 16 | grafana-cli.exe plugins install ryantxu-ajax-panel 17 | 18 | 4. Install **FlowCharting Panel** 19 | 20 | ```powershell 21 | cd "C:\Program Files\GrafanaLabs\grafana\bin" 22 | 23 | grafana-cli.exe plugins install agenty-flowcharting-panel 24 | ``` 25 | 26 | 5. Once both the plugins are installed, restart the grafana service by Opening **Services** windows application and restart Grafana service by right click on it. 27 | 28 | 29 | 2. Setting up Telegraf on Windows 30 | 31 | 1. Open a **Command Prompt** as an **Administrator**. 32 | 33 | 2. To install and setup Telegraf on windows, run the `simulator_configs/setup_telegraf.bat` file 34 | 35 | ```powershell 36 | cd \simulator_configs 37 | 38 | setup_telegraf.bat 39 | ``` 40 | 41 | 3. Run the command the below command to get the EFLOW VM IP on a power shell 42 | 43 | ```sh 44 | Get-eflowVmAddr 45 | ``` 46 | 47 | 4. Run the configuration script with the EFLOW IP from the previous step 48 | 49 | ``` 50 | cd \simulator_configs 51 | 52 | python3 configure.py -ip 53 | ``` 54 | 55 | 56 | 3. Run the below command to setup the Telegraf configuration file and create Grafana UI dashboards 57 | 58 | ```sh 59 | cd "C:\Program Files\InfluxData\telegraf\" 60 | 61 | telegraf.exe --service install --config "C:\Program Files\InfluxData\telegraf\telegraf.conf" 62 | 63 | telegraf.exe --service start 64 | ``` 65 | 66 | # Visualize Weld Porosity Edge UI - Linux on Windows 67 | 68 | * Open the URL [localhost:3000](http://localhost:5000) on your Windows Deployment machine to open the Grafana dashboard. 69 | 70 | * Open the dashboard **Edge UI - Linux** from the dashboard list. 71 | 72 | # Visualize Weld Porosity Windows HMI Simulator 73 | 74 | * Open the URL [localhost:3000](http://localhost:5000) on your Windows Deployment machine to open the Grafana dashboard. 75 | 76 | * Open the dashboard **Windows HMI Simulator** from the dashboard list. 77 | 78 | -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/simulator_configs/datasource.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"InfluxDB", 3 | "type":"influxdb", 4 | "url":"http://:8086", 5 | "access":"proxy", 6 | "isDefault":true, 7 | "database":"telegraf" 8 | } -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/simulator_configs/setup_telegraf.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | ECHO Downloading Telegraf... 3 | 4 | powershell wget https://dl.influxdata.com/telegraf/releases/telegraf-1.21.1_windows_amd64.zip -UseBasicParsing -OutFile telegraf_windows_amd64.zip 5 | 6 | ECHO Setting up Telegraf... 7 | 8 | powershell Expand-Archive -f .\telegraf_windows_amd64.zip -DestinationPath 'C:\Program Files\InfluxData\telegraf\' 9 | 10 | copy telegraf.conf "C:\Program Files\InfluxData\telegraf\" 11 | copy "C:\Program Files\InfluxData\telegraf\telegraf-1.21.1\telegraf.exe" "C:\Program Files\InfluxData\telegraf" 12 | 13 | ECHO Setting Up Telegraf is completed. 14 | ECHO Now run the configuration script and follow the document -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/.env: -------------------------------------------------------------------------------- 1 | CONTAINER_REGISTRY_USERNAME="" 2 | CONTAINER_REGISTRY_PASSWORD="" 3 | INPUT="rtsp://rtspsim:8554/input.mp4" 4 | TARGET_HARDWARE="CPU" -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/opcua/Dockerfile.opcua: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 scalers.ai 2 | 3 | FROM python:3.8-slim-buster 4 | 5 | LABEL Description="This is the base image for python based opcua server" 6 | LABEL Vendor="scalers.ai" 7 | 8 | WORKDIR /src 9 | RUN pip3 install asyncua 10 | 11 | COPY src/server.py /src/server.py 12 | 13 | EXPOSE 4840 14 | 15 | CMD ["python3", "server.py"] 16 | -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/opcua/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-version": "0.0.1", 3 | "description": "", 4 | "image": { 5 | "repository": "$CONTAINER_REGISTRY_USERNAME.azurecr.io/opecua", 6 | "tag": { 7 | "version": "0.0.1", 8 | "platforms": { 9 | "amd64": "./Dockerfile.opcua" 10 | } 11 | }, 12 | "buildOptions": [], 13 | "contextPath": "./" 14 | } 15 | } -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/opcua/src/server.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 scalers.ai 2 | 3 | import asyncio 4 | from asyncua import Server 5 | 6 | async def start_opcua_server(): 7 | """Start OPCUA server using the python package asyncua: 8 | https://github.com/FreeOpcUa/FreeOpcUa.github.io 9 | """ 10 | url = "opc.tcp://0.0.0.0:4840" 11 | 12 | server = Server() 13 | await server.init() 14 | 15 | server.set_endpoint(url) 16 | server.set_server_name("Weld Porocity OPCUA Server") 17 | 18 | # register namespace 19 | name = "OPCUA_SIMULATION_SERVER" 20 | addspace = await server.register_namespace(name) 21 | 22 | node = await server.nodes.objects.add_object(addspace, 'Parameters') 23 | 24 | # add parameters to the namespaces 25 | WeldClass = await node.add_variable(addspace, "WeldClass", 0) 26 | Probability = await node.add_variable(addspace, "Probability", 0.0) 27 | FPS = await node.add_variable(addspace, "FPS", 0.0) 28 | 29 | # set parameters to writable 30 | await WeldClass.set_writable() 31 | await Probability.set_writable() 32 | await FPS.set_writable() 33 | 34 | print("Server started at {}".format(url)) 35 | async with server: 36 | while True: 37 | await asyncio.sleep(1) 38 | 39 | if __name__ == "__main__": 40 | # start the opcua server 41 | asyncio.run(start_opcua_server()) -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/pipeline/Dockerfile.pipeline: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 scalers.ai 2 | 3 | FROM openvino/ubuntu20_data_runtime:2021.4 4 | 5 | LABEL Description="This is the base image for weld porosity recognition" 6 | LABEL Vendor="scalers.ai" 7 | 8 | USER root 9 | 10 | RUN apt-get update 11 | 12 | RUN chmod +x /opt/intel/openvino_2021/install_dependencies/install_openvino_dependencies.sh && \ 13 | cd /opt/intel/openvino_2021/install_dependencies/ && ./install_openvino_dependencies.sh -y 14 | 15 | RUN pip3 install numpy opcua 16 | 17 | COPY src /src 18 | COPY models /models 19 | 20 | WORKDIR /src 21 | 22 | RUN chmod +x run.sh 23 | 24 | CMD source /opt/intel/openvino_2021/bin/setupvars.sh && ./run.sh -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/pipeline/models/weld_porosity/FP32/weld-porosity-detection-0001.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/edge-ai-welding-demo/src/modules/pipeline/models/weld_porosity/FP32/weld-porosity-detection-0001.bin -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/pipeline/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-version": "0.0.1", 3 | "description": "", 4 | "image": { 5 | "repository": "$CONTAINER_REGISTRY_USERNAME.azurecr.io/pipeline", 6 | "tag": { 7 | "version": "0.0.1", 8 | "platforms": { 9 | "amd64": "./Dockerfile.pipeline" 10 | } 11 | }, 12 | "buildOptions": [], 13 | "contextPath": "./" 14 | } 15 | } -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/pipeline/src/run.sh: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 scalers.ai 2 | 3 | WELD_POROSITY_MODEL=/models/weld_porosity/FP32/weld-porosity-detection-0001.xml 4 | 5 | runPipeline() { 6 | gst-launch-1.0 \ 7 | rtspsrc location=$INPUT ! decodebin ! videoconvert ! video/x-raw,format=BGRx ! \ 8 | gvapython module=weld_porosity.py class=InferenceTime ! \ 9 | gvainference model=${WELD_POROSITY_MODEL} inference-interval=1 device=$DEVICE ! \ 10 | gvapython module=weld_porosity.py class=WeldPorosity ! \ 11 | gvametaconvert format=json add-tensor-data=true ! \ 12 | gvametapublish method=mqtt address=MQTTBroker:1883 topic=weld 13 | 14 | return 15 | } 16 | 17 | until runPipeline; 18 | do 19 | echo 'Restarting pipeline' 20 | sleep 1 21 | done -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/rtspsim/Dockerfile.rtspsim: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 scalers.ai 2 | 3 | FROM aler9/rtsp-simple-server AS rtsp 4 | 5 | FROM ubuntu:20.04 6 | ENV DEBIAN_FRONTEND noninteractive 7 | 8 | LABEL Description="This is the base image for rtsp simulator" 9 | LABEL Vendor="scalers.ai" 10 | 11 | RUN apt-get update && \ 12 | apt-get install -y -q --no-install-recommends python3 \ 13 | python3-opencv ffmpeg 14 | 15 | COPY --from=rtsp /rtsp-simple-server / 16 | COPY --from=rtsp /rtsp-simple-server.yml / 17 | 18 | WORKDIR / 19 | COPY src/streamer.py / 20 | COPY src/run.sh / 21 | COPY input/ /input 22 | 23 | EXPOSE 8554 24 | 25 | ENTRYPOINT [ "sh", "run.sh" ] 26 | -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/rtspsim/input/input.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/edge-ai-welding-demo/src/modules/rtspsim/input/input.mp4 -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/rtspsim/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-version": "0.0.1", 3 | "description": "", 4 | "image": { 5 | "repository": "$CONTAINER_REGISTRY_USERNAME.azurecr.io/rtspsim", 6 | "tag": { 7 | "version": "0.0.1", 8 | "platforms": { 9 | "amd64": "./Dockerfile.rtspsim" 10 | } 11 | }, 12 | "buildOptions": [], 13 | "contextPath": "./" 14 | } 15 | } -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/rtspsim/src/run.sh: -------------------------------------------------------------------------------- 1 | #sh 2 | # Copyright (C) 2021 scalers.ai 3 | 4 | ./rtsp-simple-server & \ 5 | python3 streamer.py -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/rtspsim/src/streamer.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 scalers.ai 2 | 3 | import glob 4 | import os 5 | import subprocess 6 | import cv2 7 | import time 8 | 9 | 10 | def run_streams(): 11 | """ 12 | Stream ffmpeg rtsp streams for all the mp4 files in a directory 13 | The streams will be ran on a infinite loop 14 | """ 15 | media_dir = "/input/" 16 | pipelines = {} 17 | 18 | # create streaming pipeline for all videos in input folder 19 | os.chdir(media_dir) 20 | for media in glob.glob("*.mp4"): 21 | media_path = os.path.join(media_dir, media) 22 | pipelines[media] = (["ffmpeg", "-re", "-stream_loop", "-1", "-i", media_path, "-c", 23 | "copy", "-f", "rtsp", f"rtsp://0.0.0.0:8554/{media}"]) 24 | 25 | # start all rtsp streams for pipelines created 26 | for media in pipelines: 27 | try: 28 | subprocess.run(pipelines[media]) 29 | except Exception as err: 30 | print(f"Exception {err} \n\n Exiting...") 31 | exit(1) 32 | 33 | # use opencv to check for closed rtsp streams 34 | # if any stream found closes, restart the same 35 | while True: 36 | for media in pipelines: 37 | rtsp_url = f"rtsp://localhost:8554/{media}" 38 | cap = cv2.VideoCapture(rtsp_url) 39 | if (not cap.isOpened()): 40 | print(f"[NO STREAM]: {media}") 41 | print(f"[INFO] Restarting stream for {media}") 42 | subprocess.run(pipelines[media]) 43 | else: 44 | print(f"[HEALTHY STREAM] {media}") 45 | cap.release() 46 | time.sleep(5) 47 | 48 | 49 | if __name__ == "__main__": 50 | run_streams() 51 | -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/telegraf/Dockerfile.telegraf: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 scalers.ai 2 | # Dockerfile for custom telegraf image 3 | 4 | FROM telegraf:1.22.3 5 | 6 | LABEL Description="This is the base image for weld porosity recognition telegraf" 7 | LABEL Vendor="scalers.ai" 8 | 9 | ENV DEBIAN_FRONTEND noninteractive 10 | USER root 11 | 12 | RUN apt-get update && \ 13 | apt-get install -y -q --no-install-recommends python3 \ 14 | python3-pip python3-setuptools python3-opencv 15 | 16 | WORKDIR /app 17 | 18 | COPY src/ /app/ 19 | COPY src/telegraf.conf /etc/telegraf/ 20 | 21 | RUN pip3 install -r requirements.txt 22 | 23 | EXPOSE 5100/tcp 24 | 25 | ENTRYPOINT ["/bin/bash", "/entrypoint.sh", "telegraf"] 26 | -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/telegraf/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-version": "0.0.1", 3 | "description": "", 4 | "image": { 5 | "repository": "$CONTAINER_REGISTRY_USERNAME.azurecr.io/telegraf", 6 | "tag": { 7 | "version": "0.0.1", 8 | "platforms": { 9 | "amd64": "./Dockerfile.telegraf" 10 | } 11 | }, 12 | "buildOptions": [], 13 | "contextPath": "./" 14 | } 15 | } -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/telegraf/src/image_server.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2021 scalers.ai 3 | Image server based on flask to serve images for dashboard 4 | 5 | version: 1.0 6 | """ 7 | import os 8 | import time 9 | from contextlib import contextmanager, redirect_stderr, redirect_stdout 10 | from os import devnull 11 | 12 | import cv2 13 | from flask import Flask, Response, request 14 | 15 | from mqtt_sub import MQTTSub 16 | 17 | app = Flask(__name__) 18 | MQTT_IP = os.environ['MQTT_IP'] 19 | mqtt = MQTTSub(MQTT_IP, False) 20 | 21 | 22 | @contextmanager 23 | def suppress_stdout_stderr(): 24 | """A context manager that redirects stdout and stderr to devnull""" 25 | with open(devnull, 'w') as fnull: 26 | with redirect_stderr(fnull) as err, redirect_stdout(fnull) as out: 27 | yield (err, out) 28 | 29 | 30 | def gen_live(stream_id: str) -> bytes: 31 | """ 32 | Generate live streams for an input stream ID 33 | 34 | :params stream_id: Stream ID of the pipeline 35 | 36 | :returns bytes 37 | """ 38 | while True: 39 | try: 40 | time.sleep(0.01) 41 | live = mqtt.stream_data[stream_id]['live'] 42 | except KeyError: 43 | print("Stream ID not found") 44 | continue 45 | 46 | ret, buffer = cv2.imencode('.jpg', live) 47 | if ret: 48 | frame = buffer.tobytes() 49 | yield (b'--frame\r\n' 50 | b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') 51 | 52 | 53 | @app.route('/feed') 54 | def live_feed(): 55 | """Serve video feed on path /feed""" 56 | stream_id = request.args.get('stream', default="100", type=str) 57 | return Response(gen_live(stream_id), mimetype='multipart/x-mixed-replace; boundary=frame') 58 | 59 | 60 | def main(): 61 | """Main method""" 62 | try: 63 | print("Starting Video feed server") 64 | app.run(host='0.0.0.0', port=5100, debug=True) 65 | except Exception as exc: 66 | error_msg = ("Exception while starting video feed server. " 67 | f"{type(exc).__name__}: {exc}") 68 | print(error_msg) 69 | 70 | 71 | if __name__ == '__main__': 72 | with suppress_stdout_stderr(): 73 | main() 74 | -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/telegraf/src/mqtt_sub.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin python3 2 | # Copyright (C) 2021 scalers.ai 3 | """ 4 | MQTT Subscriber script for receiving data from Weld Porosity recognition 5 | pipeline 6 | 7 | version: 1.0 8 | """ 9 | import base64 10 | import json 11 | from json import JSONDecodeError 12 | 13 | import cv2 14 | import numpy as np 15 | import paho.mqtt.client as mqtt 16 | 17 | 18 | class MQTTSub: 19 | """MQTTSub class to subscribe to weld MQTT topic""" 20 | def __init__(self, host_ip: str, is_print: bool): 21 | """Initialize MQTTSub class""" 22 | self.host_ip = host_ip 23 | self.is_print = is_print 24 | self.stream_data = { 25 | "100": { 26 | 'label': 0, 27 | 'prob': 0, 28 | 'fps': 0, 29 | 'target': 'CPU', 30 | 'live': np.zeros((64, 96, 3), dtype=np.uint8) 31 | } 32 | } 33 | self.connect() 34 | 35 | def decode(self, encoded_img: str) -> np.ndarray: 36 | """ 37 | Decode base64 encoded images received over mqtt 38 | 39 | :params encoded_img: base64 encoded image 40 | 41 | :returns img: decoded numpy array 42 | """ 43 | img_original = base64.b64decode(encoded_img) 44 | img_as_np = np.frombuffer(img_original, dtype=np.uint8) 45 | img = cv2.imdecode(img_as_np, cv2.IMREAD_COLOR) 46 | 47 | return img 48 | 49 | def on_message(self, client, userdata, msg) -> None: 50 | """MQTT on_message method""" 51 | try: 52 | payload_data = json.loads(msg.payload) 53 | except JSONDecodeError: 54 | error_msg = ("Error loading MQTT payload received. Plugin will ", 55 | "reload in 20 seconds.") 56 | exit(1) 57 | 58 | try: 59 | stream = payload_data['stream'] 60 | if self.is_print: 61 | weld_class = payload_data['label'] 62 | probability = payload_data['prob'] 63 | fps = payload_data['fps'] 64 | target = payload_data['target'] 65 | 66 | self.stream_data = { 67 | stream: { 68 | 'label': weld_class, 69 | 'prob': probability, 70 | 'fps': fps, 71 | 'target': target 72 | } 73 | } 74 | else: 75 | org_img = payload_data['image'] 76 | 77 | except KeyError: 78 | error_msg = ("Error loading image/count details from payload. ", 79 | "Plugin will reload in 20 seconds") 80 | exit(1) 81 | 82 | if not self.is_print: 83 | try: 84 | live = self.decode(org_img) 85 | except Exception as exc: 86 | error_msg = f"{type(exc).__name__}: {exc}" 87 | print(error_msg) 88 | exit(1) 89 | 90 | self.stream_data = { 91 | stream: { 92 | 'live': live 93 | } 94 | } 95 | 96 | def connect(self) -> None: 97 | """Connect to MQTT Server and run loop in seperate thread""" 98 | client = mqtt.Client() 99 | try: 100 | client.connect(self.host_ip) 101 | except Exception as exc: 102 | error_msg = ("Error connectint to MQTT Server. \n" 103 | f"{type(exc).__name__}: {exc}") 104 | print(error_msg) 105 | exit(1) 106 | 107 | client.subscribe("weld") 108 | client.on_message = self.on_message 109 | print("Connected to MQTT Server successfully.") 110 | # start client loop in seperate thread 111 | client.loop_start() 112 | -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/telegraf/src/print_count.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin python3 2 | # Copyright (C) 2021 scalers.ai 3 | # Version: 1.0 4 | 5 | import os 6 | import time 7 | 8 | from mqtt_sub import MQTTSub 9 | 10 | 11 | def print_count() -> None: 12 | """Print inference results by reading data from MQTTSub class""" 13 | MQTT_IP = os.environ['MQTT_IP'] 14 | mqtt = MQTTSub(MQTT_IP, True) 15 | 16 | while True: 17 | current_time = int(time.time() * 1000000000) 18 | stream_data = mqtt.stream_data 19 | stream = next(iter(stream_data.keys())) 20 | 21 | line = ("weld,stream={} weld_class={},fps={},prob={},target=\"{}\"" 22 | " {} \n").format( 23 | stream, stream_data[stream]['label'], 24 | stream_data[stream]['fps'], 25 | stream_data[stream]['prob'], 26 | stream_data[stream]['target'], 27 | current_time 28 | ) 29 | print(line) 30 | time.sleep(0.001) 31 | 32 | 33 | if __name__ == "__main__": 34 | print_count() 35 | -------------------------------------------------------------------------------- /samples/edge-ai-welding-demo/src/modules/telegraf/src/requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==1.22.0 2 | paho-mqtt==1.6.1 3 | flask==2.3.2 -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Create Certificates for Authentication.MD: -------------------------------------------------------------------------------- 1 | # Text Messaging & Custom Vision Interop Samples 2 | ## Progress 3 | 4 | - [x] [Introduction](../README.md) 5 | - [x] [Step 1 - Setup Azure Resources](./Setup%20Azure%20Resources.MD) 6 | - [x] [Step 2 - Setup Azure IoT Edge for Linux on Windows](./Setup%20Azure%20IoT%20Edge%20for%20Linux%20on%20Windows.MD) 7 | - [x] [Step 3 - Develop and publish the IoT Edge Linux module](./Develop%20and%20publish%20the%20IoT%20edge%20Linux%20module.MD) 8 | - [ ] **Step 4 - Create Certificates for Authentication** 9 | - [ ] [Step 5 - Develop the Windows C# UWP Application](./Develop%20the%20Windows%20C%23%20UWP%20Application.MD) 10 | - [ ] [Step 6 - Configuring the IoT Edge Device](./Configuring%20the%20IoT%20Edge%20Device.MD) 11 | - [ ] [Step 7 - Run samples](./Run%20samples.MD) 12 | - [ ] [Troubleshooting](./Troubleshooting.MD) 13 | --- 14 | # Step 4: Create Certificates for Authentication 15 | This part describes the relevant steps to create sample certificates for the authentication between downstream device and IoT edge. 16 | 17 | * **To create a sample PKI with certificate validity for one month** 18 | Complete the steps within the steps of [Create demo certificates to test IoT Edge device features](https://learn.microsoft.com/en-us/azure/iot-edge/how-to-create-transparent-gateway?view=iotedge-1.4&tabs=eflow#create-demo-certificates). 19 | 20 | * **To generate customizable test certificates** 21 | Follow the steps described in [Generate test certificates for Edge Gateway](https://github.com/Azure-Samples/IoTEdgeAndMlSample/tree/master/CreateCertificates) to create sample certificates to use for the interop solution. It generates certificates with default subject name "turbofanGateway" and 30 days validity. To extend the validity of certificates (or) to change the subject name, make the following modifications to **dockerfile** then re-build the docker image. 22 | 23 | You can also use your own root CA certificate in case you have a (test) PKI for downstream devices and edge devices. In any of the two latter cases, replace the private key, certificate chain, and root CA cert. 24 | 25 | Go to [Next Step](./Develop%20the%20Windows%20C%23%20UWP%20Application.MD) 26 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Deploy the Modules onto the IoT Edge Device.MD: -------------------------------------------------------------------------------- 1 | # Text Messaging & Custom Vision Interop Samples 2 | ## Progress 3 | 4 | - [x] [Introduction](../README.md) 5 | - [x] [Step 1 - Setup Azure Resources](./Setup%20Azure%20Resources.MD) 6 | - [x] [Step 2 - Setup Azure IoT Edge for Linux on Windows](./Setup%20Azure%20IoT%20Edge%20for%20Linux%20on%20Windows.MD) 7 | - [x] [Step 3 - Develop and publish the IoT Edge Linux module](./Develop%20and%20publish%20the%20IoT%20edge%20Linux%20module.MD) 8 | - [x] [Step 4 - Create Certificates for Authentication](./Create%20Certificates%20for%20Authentication.MD) 9 | - [x] [Step 5 - Develop the Windows C# Console Application](./Develop%20the%20Windows%20C%23%20Console%20Application.MD) 10 | - [x] [Step 6 - Configuring the IoT Edge Device](./Configuring%20the%20IoT%20Edge%20Device.MD) 11 | - [ ] **Step 7 - Deploy the Modules onto the IoT Edge Device** 12 | - [ ] [Step 8 - Run samples](./Run%20samples.MD) 13 | --- 14 | 15 | # Step 7: Deploy the Modules onto the IoT Edge Device 16 | Having the IoT Edge device set up, we now deploy the Linux modules onto the device. 17 | 18 | ## Steps in the development VM 19 | 20 | 1. Perform the following steps from **Deploy Azure IoT Edge modules from Visual Studio Code** documentation. 21 | * [Sign in to access your IoT Hub](https://docs.microsoft.com/azure/iot-edge/how-to-deploy-modules-vscode#sign-in-to-access-your-iot-hub) 22 | * [Deploy to your device](https://docs.microsoft.com/azure/iot-edge/how-to-deploy-modules-vscode#deploy-to-your-device) 23 | (Select the file **deployment.amd64.json** from the **config** folder as manifest file to be deployed.) 24 | 25 | * [View modules on your device](https://docs.microsoft.com/azure/iot-edge/how-to-deploy-modules-vscode#view-modules-on-your-device) 26 | 27 | ## Steps in the Linux environment of the IoT Edge Device 28 | Using the Linux command shell that you signed into in [Step 6.2](./Configuring%20the%20IoT%20Edge%20Device.MD), run the following command to see the modules that have been deployed to your edge device. 29 | 30 | ```powershell 31 | sudo iotedge list 32 | ``` 33 | 34 | You should see the CSharpModule like the following: 35 | 36 | ![Console Application](./Images/IoTEdgeList2.png) 37 | 38 | 39 | Go to [Next Step](./Run%20samples.MD) 40 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Develop and publish the IoT edge Linux module.MD: -------------------------------------------------------------------------------- 1 | # Text Messaging & Custom Vision Interop Samples 2 | ## Progress 3 | 4 | - [x] [Introduction](../README.md) 5 | - [x] [Step 1 - Setup Azure Resources](./Setup%20Azure%20Resources.MD) 6 | - [x] [Step 2 - Setup Azure IoT Edge for Linux on Windows](./Setup%20Azure%20IoT%20Edge%20for%20Linux%20on%20Windows.MD) 7 | - [ ] **Step 3 - Develop and publish the IoT Edge Linux module** 8 | - [ ] [Step 4 - Create Certificates for Authentication](./Create%20Certificates%20for%20Authentication.MD) 9 | - [ ] [Step 5 - Develop the Windows C# UWP Application](./Develop%20the%20Windows%20C%23%20UWP%20Application.MD) 10 | - [ ] [Step 6 - Configuring the IoT Edge Device](./Configuring%20the%20IoT%20Edge%20Device.MD) 11 | - [ ] [Step 7 - Run samples](./Run%20samples.MD) 12 | - [ ] [Troubleshooting](./Troubleshooting.MD) 13 | --- 14 | # Step 3: Develop and publish the IoT Edge Linux module 15 | In this part, we develop and publish the Linux modules in the Windows host using Visual Studio Code. 16 | 17 | Build the sample Linux modules in VS Code and add them to your Azure Registry. 18 | 19 | 1. Open VS Code as an administrator 20 | 21 | 2. Open the below folder in VS Code based on the sample you are running: 22 | - Text Messaging: ` Windows-IoT-Samples\interop-customvision-textmsg-uwpapp\textmsg-uwpapp` 23 | - Custom Vision: `Windows-IoT-Samples\interop-customvision-textmsg-uwpapp\customvision` 24 | 25 | 3. Create an **.env** file in this folder with the container registry authentication details as variables: 26 | 27 | ``` 28 | CONTAINER_REGISTRY_USERNAME_=XXX 29 | CONTAINER_REGISTRY_PASSWORD_=XXX 30 | ``` 31 | 32 | 4. Replace the two 'XXX' in the .env file by setting the username and password for your container registry as found in the Azure portal. Navigate to your container registry in the Azure portal and go to the tab 'Access Keys'. 33 | 34 | 5. Replace all occurrences of 'partnercontainerregistry' in the already opened folder with your own registry's name in lower case letters, for example, with 'interopsampleregistry' if you called your registry that way (using VS Code, you can press CTRL+SHIFT+F to search and replace all occurrences). 35 | 36 | 6. Ensure to be logged in to the Azure portal. VS Code will query you to do so. 37 | 38 | 7. Ensure the docker daemon is running, if not start it. 39 | 40 | 8. Also ensure to be logged in with the Azure Registry itself using the credentials shown in the Azure portal: 41 | 42 | ``` 43 | docker login interopsampleregistry.azurecr.io 44 | ``` 45 | 46 | 9. Right click on the *deployment.template.json* file, click on *Build & push module* 47 | 48 | 10. Create an IoT Deployment containing the Linux modules and add it to our sample IoT Edge Device: 49 | - This means to deploy the deployment manifest i.e. deployment.template.json onto your IoT Edge device. 50 | - Using VS code, follow the steps from the documentation [Deploy Azure IoT Edge modules from Visual Studio Code](https://docs.microsoft.com/azure/iot-edge/how-to-deploy-modules-vscode): 51 | - Select 'deployment.template.json', right-click and select 'Generate IoT Edge Deployment Manifest' 52 | - Choose your subscription, IoT Hub, right-click on the Edge Device and select 'Create Deployment for Single Device' 53 | - Select the file 'deployment.amd64.json' in the folder 'config' and push the deployment manifest. 54 | 55 | > **Note:** 56 | > If the multiple container deployment fails, try to push each module separately using the *module.json* file. 57 | 58 | 59 | Go to [Next Step](./Create%20Certificates%20for%20Authentication.MD) 60 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Images/BuildAndPushError.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/Documentation/Images/BuildAndPushError.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Images/LogError.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/Documentation/Images/LogError.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Images/TLS_Error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/Documentation/Images/TLS_Error.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Images/fruitclassifier-sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/Documentation/Images/fruitclassifier-sample.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Images/processingmodule-sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/Documentation/Images/processingmodule-sample.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Images/proxymodule-sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/Documentation/Images/proxymodule-sample.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Images/uwp-app-message-sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/Documentation/Images/uwp-app-message-sample.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Images/uwp-app-setup-sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/Documentation/Images/uwp-app-setup-sample.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Images/winapp-sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/Documentation/Images/winapp-sample.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Setup Azure IoT Edge for Linux on Windows.MD: -------------------------------------------------------------------------------- 1 | # Text Messaging & Custom Vision Interop Samples 2 | ## Progress 3 | 4 | - [x] [Introduction](../README.md) 5 | - [x] [Step 1 - Setup Azure Resources](./Setup%20Azure%20Resources.MD) 6 | - [ ] **Step 2 - Setup Azure IoT Edge for Linux on Windows** 7 | - [ ] [Step 3 - Develop and publish the IoT Edge Linux module](./Develop%20and%20publish%20the%20IoT%20edge%20Linux%20module.MD) 8 | - [ ] [Step 4 - Create Certificates for Authentication](./Create%20Certificates%20for%20Authentication.MD) 9 | - [ ] [Step 5 - Develop the Windows C# UWP Application](./Develop%20the%20Windows%20C%23%20UWP%20Application.MD) 10 | - [ ] [Step 6 - Configuring the IoT Edge Device](./Configuring%20the%20IoT%20Edge%20Device.MD) 11 | - [ ] [Step 7 - Run samples](./Run%20samples.MD) 12 | - [ ] [Troubleshooting](./Troubleshooting.MD) 13 | --- 14 | # Step 2: Setup Azure IoT Edge for Linux on Windows 15 | This part describes the relevant steps to set up Azure IoT Edge for Linux on Windows (EFLOW). 16 | 17 | * **To create a EFLOW device** 18 | Complete the steps described in [Install and provision Azure IoT Edge for Linux on a Windows device](https://learn.microsoft.com/azure/iot-edge/how-to-provision-single-device-linux-on-windows-symmetric?view=iotedge-1.4&tabs=azure-portal%2Cpowershell) guide. 19 | 20 | * **To learn more about EFLOW** 21 | For more information, review [EFLOW docs](https://learn.microsoft.com/en-us/azure/iot-edge/iot-edge-for-linux-on-windows?view=iotedge-1.4). 22 | 23 | 24 | Go to [Next Step](./Develop%20and%20publish%20the%20IoT%20edge%20Linux%20module.MD) 25 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/Documentation/Troubleshooting.MD: -------------------------------------------------------------------------------- 1 | ## Troubleshooting 2 | 3 | ## Progress 4 | 5 | - [x] [Introduction](../README.md) 6 | - [x] [Step 1 - Setup Azure Resources](./Setup%20Azure%20Resources.MD) 7 | - [x] [Step 2 - Setup Azure IoT Edge for Linux on Windows](./Setup%20Azure%20IoT%20Edge%20for%20Linux%20on%20Windows.MD) 8 | - [x] [Step 3 - Develop and publish the IoT Edge Linux module](./Develop%20and%20publish%20the%20IoT%20edge%20Linux%20module.MD) 9 | - [x] [Step 4 - Create Certificates for Authentication](./Create%20Certificates%20for%20Authentication.MD) 10 | - [x] [Step 5 - Develop the Windows C# Console Application](./Develop%20the%20Windows%20C%23%20Console%20Application.MD) 11 | - [x] [Step 6 - Configuring the IoT Edge Device](./Configuring%20the%20IoT%20Edge%20Device.MD) 12 | - [x] [Step 7 - Run samples](./Run%20samples.MD) 13 | - [ ] **Troubleshooting** 14 | --- 15 | 16 | 17 | #### 1. Console message app shows TLS Error #### 18 | This problem is usually caused by a gateway issue. On the IoT Edge device configuration (/etc/iotedge/config.yaml) there's a section called hostname. This automatically gets populated with the system hostname. In some cases, hostname is not found and the user will have to use the EFLOW VM IP. Ensure the gateway name in the C# Windows app matches the hostname in the IoT Edge config.yaml. 19 | 20 | ![TLS Error](./Images/TLS_Error.png) 21 | 22 | If the previous steps doesn't work, follow these steps: 23 | 1. In the config.yaml, change the hostname to the IP address of the EFLOW VM. 24 | 2. `sudo systemctl restart aziot*` 25 | 3. `sudo systemctl status aziot*` - Make sure it says active (running) 26 | 4. `sudo iotedge check` 27 | 5. Run the c# console app using the IP address for the gateway address insted of the hostname 28 |
29 | 30 | 31 | > **Note:** You might get an error related to "correct hostname"; however the IoT Edge should work correctly anyway 32 | > ![LogError](./Images/LogError.png) 33 | 34 | 35 | #### 2. Error when pushing a module to Azure Contianer Registry #### 36 | To fix an error when pushing the container, ensure that the module.json has the proper registry and container name appended: .azurecr.io/. For more information, visit [Can't Push IoT Edge module to Azure Container Registry](https://github.com/MicrosoftDocs/azure-docs/issues/22296). 37 |

38 | 39 | #### 3. Error when pushing a deploying the CSharpModule app #### 40 | To fix this error, change InteropSampleRegistry value in the registry credentials to direct values or add a separate environment variable for the registry container. 41 |

42 | 43 | #### 4. Operation is not valid due to the current state of the object in microsoft.azure.amqp #### 44 | This is a bug in AMQP and .NET 5. For more information about this error, check this [thread](https://stackoverflow.com/questions/64804036/operation-is-not-valid-due-to-the-current-state-of-the-object-source-microsoft). The solution is adding AMQP version requirement, as well as using .NET Core 3.1LTS instead of .NET 5 45 | ```csharp 46 | 47 | ``` 48 |
49 | 50 | #### 5. Modules not showing up in the IoT Edge device #### 51 | This error is generally related to an authentication issue when pulling the module from the container registry. For further information, use the IoTEdge logs. 52 | ```powershell 53 | sudo iotedge logs edgeAgent 54 | sudo iotedge logs edgeHub 55 | ``` 56 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Text Messaging & Custom Vision Interop Samples 3 | 4 | This document uses two samples to demonstrate how Windows applications interoperate with Azure IoT Edge for Linux modules in the EFLOW VM. 5 | 6 | 1. **Simple Text Messaging** 7 | Demonstrates minimalistic text message exchange between a Windows application and an Azure IoT Edge for Linux module. 8 | 9 | 2. **Custom Vision** 10 | Demonstrates machine learning modules in Azure IoT Edge for Linux in which a Windows application sends camera frames to a Linux module and receives back a description of an item presented to the camera. 11 | 12 | 13 | **Prerequisites** 14 | - An Azure subscription. 15 | - Basic knowledge of the Azure Cloud portal and its use 16 | - Windows 10 PC with PowerShell to set up an Azure Virtual Machine as your development environment. 17 | - Text Messaging 18 | - A physical/emulated Windows host device. 19 | - Custom Vision based on [Tutorial: Perform image classification at the edge with Custom Vision Service](https://docs.microsoft.com/azure/iot-edge/tutorial-deploy-custom-vision) 20 | - A physical Windows host device with a USB Camera connected. 21 | - Fruits for object classification. 22 | 23 | ## Instructions 24 | [Step 1 - Setup Azure Resources](./Documentation/Setup%20Azure%20Resources.MD) 25 | [Step 2 - Setup Azure IoT Edge for Linux on Windows](./Documentation/Setup%20Azure%20IoT%20Edge%20for%20Linux%20on%20Windows.MD) 26 | [Step 3 - Develop and publish the IoT Edge Linux module](./Documentation/Develop%20and%20publish%20the%20IoT%20edge%20Linux%20module.MD) 27 | [Step 4 - Create Certificates for Authentication](./Documentation/Create%20Certificates%20for%20Authentication.MD) 28 | [Step 5 - Develop the Windows C# UWP Application](./Documentation//Develop%20the%20Windows%20C%23%20UWP%20Application.MD) 29 | [Step 6 - Configuring the IoT Edge Device](./Documentation/Configuring%20the%20IoT%20Edge%20Device.MD) 30 | [Step 7 - Run samples](./Documentation//Run%20samples.MD) 31 | [Troubleshooting](./Documentation//Troubleshooting.MD) 32 | 33 | 34 | ## Feedback 35 | If you have problems with this sample, please post an issue in this repository. 36 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/.gitignore: -------------------------------------------------------------------------------- 1 | config/ 2 | .env 3 | DeviceCustomVisionUWPApp/.vs/ 4 | DeviceCustomVisionUWPApp/bin/ 5 | DeviceCustomVisionUWPApp/obj/ 6 | DeviceCustomVisionUWPApp/x64/ -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/App.xaml.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using Windows.ApplicationModel; 6 | using Windows.ApplicationModel.Activation; 7 | using Windows.UI.Xaml; 8 | using Windows.UI.Xaml.Controls; 9 | using Windows.UI.Xaml.Navigation; 10 | 11 | namespace DeviceCustomVisionUWPApp 12 | { 13 | /// 14 | /// Provides application-specific behavior to supplement the default Application class. 15 | /// 16 | sealed partial class App : Application 17 | { 18 | /// 19 | /// Initializes the singleton application object. This is the first line of authored code 20 | /// executed, and as such is the logical equivalent of main() or WinMain(). 21 | /// 22 | public App() 23 | { 24 | this.InitializeComponent(); 25 | this.Suspending += OnSuspending; 26 | } 27 | 28 | /// 29 | /// Invoked when the application is launched normally by the end user. Other entry points 30 | /// will be used such as when the application is launched to open a specific file. 31 | /// 32 | /// Details about the launch request and process. 33 | protected override void OnLaunched(LaunchActivatedEventArgs e) 34 | { 35 | Frame rootFrame = Window.Current.Content as Frame; 36 | 37 | // Do not repeat app initialization when the Window already has content, 38 | // just ensure that the window is active 39 | if (rootFrame == null) 40 | { 41 | // Create a Frame to act as the navigation context and navigate to the first page 42 | rootFrame = new Frame(); 43 | 44 | rootFrame.NavigationFailed += OnNavigationFailed; 45 | // Place the frame in the current Window 46 | Window.Current.Content = rootFrame; 47 | } 48 | 49 | if (e.PrelaunchActivated == false) 50 | { 51 | if (rootFrame.Content == null) 52 | { 53 | // When the navigation stack isn't restored navigate to the first page, 54 | // configuring the new page by passing required information as a navigation 55 | // parameter 56 | rootFrame.Navigate(typeof(MainPage), e.Arguments); 57 | } 58 | // Ensure the current window is active 59 | Window.Current.Activate(); 60 | } 61 | } 62 | 63 | /// 64 | /// Invoked when Navigation to a certain page fails 65 | /// 66 | /// The Frame which failed navigation 67 | /// Details about the navigation failure 68 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 69 | { 70 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 71 | } 72 | 73 | /// 74 | /// Invoked when application execution is being suspended. Application state is saved 75 | /// without knowing whether the application will be terminated or resumed with the contents 76 | /// of memory still intact. 77 | /// 78 | /// The source of the suspend request. 79 | /// Details about the suspend request. 80 | private void OnSuspending(object sender, SuspendingEventArgs e) 81 | { 82 | var deferral = e.SuspendingOperation.GetDeferral(); 83 | deferral.Complete(); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/StoreLogo.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/CertificateManager.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.IO; 6 | using System.Security.Cryptography.X509Certificates; 7 | 8 | namespace DeviceCustomVisionUWPApp 9 | { 10 | internal class CertificateManager 11 | { 12 | /// 13 | /// Add certificate in local cert store for use by downstream device 14 | /// client for secure connection to IoT Edge runtime. 15 | /// 16 | /// Note: On Windows machines, if you have not run this from an Administrator prompt, 17 | /// a prompt will likely come up to confirm the installation of the certificate. 18 | /// This usually happens the first time a certificate will be installed. 19 | /// 20 | public static void InstallCACert(string certificatePath) 21 | { 22 | if (string.IsNullOrWhiteSpace(certificatePath)) 23 | { 24 | throw new ArgumentNullException(nameof(certificatePath)); 25 | } 26 | 27 | Console.WriteLine($"User configured CA certificate path: {certificatePath}"); 28 | if (!File.Exists(certificatePath)) 29 | { 30 | // cannot proceed further without a proper cert file 31 | Console.WriteLine($"Invalid certificate file: {certificatePath}"); 32 | throw new InvalidOperationException("Invalid certificate file."); 33 | } 34 | else 35 | { 36 | Console.WriteLine($"Attempting to install CA certificate: {certificatePath}"); 37 | var store = new X509Store(StoreName.Root, StoreLocation.CurrentUser); 38 | store.Open(OpenFlags.ReadWrite); 39 | store.Add(new X509Certificate2(X509Certificate2.CreateFromCertFile(certificatePath))); 40 | Console.WriteLine($"Successfully added certificate: {certificatePath}"); 41 | store.Close(); 42 | } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/DeviceCustomVisionUWPApp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29728.190 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceCustomVisionUWPApp", "DeviceCustomVisionUWPApp.csproj", "{53F49575-5660-43E8-AA48-2E23D60C6153}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|ARM64 = Debug|ARM64 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|ARM = Release|ARM 15 | Release|ARM64 = Release|ARM64 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|ARM.ActiveCfg = Debug|ARM 21 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|ARM.Build.0 = Debug|ARM 22 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|ARM.Deploy.0 = Debug|ARM 23 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|ARM64.ActiveCfg = Debug|ARM64 24 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|ARM64.Build.0 = Debug|ARM64 25 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|ARM64.Deploy.0 = Debug|ARM64 26 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|x64.ActiveCfg = Debug|x64 27 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|x64.Build.0 = Debug|x64 28 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|x64.Deploy.0 = Debug|x64 29 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|x86.ActiveCfg = Debug|x86 30 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|x86.Build.0 = Debug|x86 31 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|x86.Deploy.0 = Debug|x86 32 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|ARM.ActiveCfg = Release|ARM 33 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|ARM.Build.0 = Release|ARM 34 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|ARM.Deploy.0 = Release|ARM 35 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|ARM64.ActiveCfg = Release|ARM64 36 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|ARM64.Build.0 = Release|ARM64 37 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|ARM64.Deploy.0 = Release|ARM64 38 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|x64.ActiveCfg = Release|x64 39 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|x64.Build.0 = Release|x64 40 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|x64.Deploy.0 = Release|x64 41 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|x86.ActiveCfg = Release|x86 42 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|x86.Build.0 = Release|x86 43 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|x86.Deploy.0 = Release|x86 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {5C42CFBB-B39B-4888-BEAF-A2E7B61A5FC9} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | DeviceCustomVisionUWPApp 19 | mdatla 20 | Assets\StoreLogo.png 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 35 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DeviceCustomVisionUWPApp")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DeviceCustomVisionUWPApp")] 13 | [assembly: AssemblyCopyright("Copyright © 2020")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/pear.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/customvision/DeviceCustomVisionUWPApp/pear.jpg -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7-slim 2 | 3 | RUN pip install -U pip 4 | RUN pip install numpy==1.17.3 tensorflow==2.0.0 flask pillow 5 | 6 | COPY app /app 7 | 8 | # By default, we run manual image resizing to maintain parity with CVS webservice prediction results. 9 | # If parity is not required, you can enable faster image resizing by uncommenting the following lines. 10 | # RUN echo "deb http://security.debian.org/debian-security jessie/updates main" >> /etc/apt/sources.list & apt update -y 11 | # RUN apt install -y libglib2.0-bin libsm6 libxext6 libxrender1 libjasper-dev libpng16-16 libopenexr23 libgstreamer1.0-0 libavcodec58 libavformat58 libswscale5 libqtgui4 libqt4-test libqtcore4 12 | # RUN pip install opencv-python 13 | 14 | # Expose the port 15 | EXPOSE 80 16 | 17 | # Set the working directory 18 | WORKDIR /app 19 | 20 | # Run the flask server for the endpoints 21 | CMD python -u app.py -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/Dockerfile.amd64: -------------------------------------------------------------------------------- 1 | FROM amd64/python:3.7-slim-buster 2 | 3 | WORKDIR /app 4 | 5 | COPY requirements.txt ./ 6 | RUN pip install -r requirements.txt 7 | 8 | COPY . . 9 | 10 | CMD [ "python3", "-u", "./main.py" ] -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/Dockerfile.amd64.debug: -------------------------------------------------------------------------------- 1 | FROM amd64/python:3.7-slim-buster 2 | 3 | WORKDIR /app 4 | 5 | RUN pip install ptvsd==4.1.3 6 | COPY requirements.txt ./ 7 | RUN pip install -r requirements.txt 8 | 9 | COPY . . 10 | 11 | CMD [ "python3", "-u", "./main.py" ] -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/README.txt: -------------------------------------------------------------------------------- 1 | # Custom Vision Dockerfile 2 | Exported from customvision.ai. 3 | 4 | ## Build 5 | 6 | ```bash 7 | docker build -t . 8 | ``` 9 | 10 | ### Build ARM container on x64 machine 11 | 12 | Export "ARM" Dockerfile from customvision.ai. Then build it using docker buildx command. 13 | ```bash 14 | docker buildx build --platform linux/arm/v7 -t --load . 15 | ``` 16 | 17 | ## Run the container locally 18 | ```bash 19 | docker run -p 127.0.0.1:80:80 -d 20 | ``` 21 | 22 | ## Image resizing 23 | By default, we run manual image resizing to maintain parity with CVS webservice prediction results. 24 | If parity is not required, you can enable faster image resizing by uncommenting the lines installing OpenCV in the Dockerfile. 25 | 26 | Then use your favorite tool to connect to the end points. 27 | 28 | POST http://127.0.0.1/image with multipart/form-data using the imageData key 29 | e.g 30 | curl -X POST http://127.0.0.1/image -F imageData=@some_file_name.jpg 31 | 32 | POST http://127.0.0.1/image with application/octet-stream 33 | e.g. 34 | curl -X POST http://127.0.0.1/image -H "Content-Type: application/octet-stream" --data-binary @some_file_name.jpg 35 | 36 | POST http://127.0.0.1/url with a json body of { "url": "" } 37 | e.g. 38 | curl -X POST http://127.0.0.1/url -d '{ "url": "" }' 39 | 40 | For information on how to use these files to create and deploy through AzureML check out the readme.txt in the azureml directory. 41 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/app/app.py: -------------------------------------------------------------------------------- 1 | 2 | import json 3 | import os 4 | import io 5 | 6 | # Imports for the REST API 7 | from flask import Flask, request, jsonify 8 | 9 | # Imports for image procesing 10 | from PIL import Image 11 | 12 | # Imports for prediction 13 | from predict import initialize, predict_image, predict_url 14 | 15 | app = Flask(__name__) 16 | 17 | # 4MB Max image size limit 18 | app.config['MAX_CONTENT_LENGTH'] = 4 * 1024 * 1024 19 | 20 | # Default route just shows simple text 21 | @app.route('/') 22 | def index(): 23 | return 'CustomVision.ai model host harness' 24 | 25 | # Like the CustomVision.ai Prediction service /image route handles either 26 | # - octet-stream image file 27 | # - a multipart/form-data with files in the imageData parameter 28 | @app.route('/image', methods=['POST']) 29 | @app.route('//image', methods=['POST']) 30 | @app.route('//image/nostore', methods=['POST']) 31 | @app.route('//classify/iterations//image', methods=['POST']) 32 | @app.route('//classify/iterations//image/nostore', methods=['POST']) 33 | @app.route('//detect/iterations//image', methods=['POST']) 34 | @app.route('//detect/iterations//image/nostore', methods=['POST']) 35 | def predict_image_handler(project=None, publishedName=None): 36 | try: 37 | imageData = None 38 | if ('imageData' in request.files): 39 | imageData = request.files['imageData'] 40 | elif ('imageData' in request.form): 41 | imageData = request.form['imageData'] 42 | else: 43 | imageData = io.BytesIO(request.get_data()) 44 | 45 | img = Image.open(imageData) 46 | results = predict_image(img) 47 | return jsonify(results) 48 | except Exception as e: 49 | print('EXCEPTION:', str(e)) 50 | return 'Error processing image', 500 51 | 52 | 53 | # Like the CustomVision.ai Prediction service /url route handles url's 54 | # in the body of hte request of the form: 55 | # { 'Url': ''} 56 | @app.route('/url', methods=['POST']) 57 | @app.route('//url', methods=['POST']) 58 | @app.route('//url/nostore', methods=['POST']) 59 | @app.route('//classify/iterations//url', methods=['POST']) 60 | @app.route('//classify/iterations//url/nostore', methods=['POST']) 61 | @app.route('//detect/iterations//url', methods=['POST']) 62 | @app.route('//detect/iterations//url/nostore', methods=['POST']) 63 | def predict_url_handler(project=None, publishedName=None): 64 | try: 65 | image_url = json.loads(request.get_data().decode('utf-8'))['url'] 66 | results = predict_url(image_url) 67 | return jsonify(results) 68 | except Exception as e: 69 | print('EXCEPTION:', str(e)) 70 | return 'Error processing image' 71 | 72 | if __name__ == '__main__': 73 | # Load and intialize the model 74 | initialize() 75 | 76 | # Run the server 77 | app.run(host='0.0.0.0', port=80) 78 | 79 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/app/labels.txt: -------------------------------------------------------------------------------- 1 | apple 2 | pear -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/app/model.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/app/model.pb -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/app/requirements.txt: -------------------------------------------------------------------------------- 1 | pillow==10.0.1 2 | tensorflow==2.11.1 3 | numpy==1.22.0 4 | flask==2.3.2 5 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/azureml/README.txt: -------------------------------------------------------------------------------- 1 | How to build and deploy an AzureML Image using this package 2 | =========================================================== 3 | 4 | First you need a few files from the docker app. 5 | 6 | Assuming you are in the azureml subdirectory run the following: 7 | 8 | copy ..\app\requirements.txt 9 | copy ..\app\predict.py 10 | copy ..\app\model.pb 11 | copy ..\app\labels.txt 12 | 13 | These 4 files along with the score.py file will make up the assets needed to create an AzureML image. 14 | 15 | Using the Azure ML Command Line Interface you can create and deploy a service using the following steps. 16 | 17 | If you haven't previously setup a Model Management account, please follow the instructions at https://docs.microsoft.com/en-us/azure/machine-learning/preview/deployment-setup-configuration 18 | 19 | 1. Create a manifest to describe the image creation. 20 | 21 | az ml manifest create --manifest-name -m model.pb -d labels.txt -d predict.py -r python -p requirements.txt -f score.py 22 | 23 | When this runs you'll see the following output: 24 | 25 | model.pb 26 | Successfully registered model 27 | Id: 28 | More information: 'az ml model show -m ' 29 | Creating new driver at C:\Users\\AppData\Local\Temp\tmp3i9c498m.py 30 | labels.txt 31 | predict.py 32 | score.py 33 | Successfully created manifest 34 | Id: 35 | More information: 'az ml manifest show -i 36 | 37 | 38 | 2. Create an image from the manifest 39 | 40 | az ml image create --manifest-id -n 41 | 42 | When this runs you'll see the following output: 43 | 44 | Creating image...................Done. 45 | Image ID: 46 | More details: 'az ml image show -i ' 47 | Usage information: 'az ml image usage -i ' 48 | 49 | 3. Create a realtime service to serve your model 50 | 51 | az ml service create realtime -n --image-id 52 | 53 | This will now create and deploy a service. When successful it will log some usage information that will show you how 54 | to connect to and test the service. 55 | 56 | For more information please see: 57 | https://docs.microsoft.com/en-us/azure/machine-learning/preview/model-management-service-deploy 58 | https://docs.microsoft.com/en-us/azure/machine-learning/preview/model-management-custom-container 59 | https://docs.microsoft.com/en-us/azure/machine-learning/preview/deploy-to-iot-edge-device -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/azureml/score.py: -------------------------------------------------------------------------------- 1 | from predict import initialize, predict_url, predict_image 2 | from PIL import Image 3 | import numpy as np 4 | 5 | import base64 6 | import io 7 | import json 8 | 9 | # Azure ML model loader 10 | def init(): 11 | initialize() 12 | 13 | # Helper to predict an image encoded as base64 14 | def predict_image_base64(encoded_image): 15 | if encoded_image.startswith('b\''): 16 | encoded_image = encoded_image[2:-1] 17 | 18 | decoded_img = base64.b64decode(encoded_image.encode('utf-8')) 19 | img_buffer = io.BytesIO(decoded_img) 20 | 21 | image = Image.open(io.BytesIO(decoded_img)) 22 | return predict_image(image) 23 | 24 | # Azure ML entry point 25 | def run(json_input): 26 | try: 27 | results = None 28 | input = json.loads(json_input) 29 | url = input.get("url", None) 30 | image = input.get("image", None) 31 | 32 | if url: 33 | results = predict_url(url) 34 | elif image: 35 | results = predict_image_base64(image) 36 | else: 37 | raise Exception("Invalid input. Expected url or image") 38 | return (results) 39 | except Exception as e: 40 | return (str(e)) 41 | 42 | if __name__ == "__main__": 43 | init() 44 | 45 | # test image 46 | 47 | image = Image.open("test_image.jpg") 48 | imgio = io.BytesIO() 49 | image.save(imgio, "PNG") 50 | imgio.seek(0) 51 | dataimg = base64.b64encode(imgio.read()) 52 | input = '{"image": "' + dataimg.decode('utf-8') + '"}' 53 | print ("calling") 54 | result = run(input) 55 | input_url = '{"url": "https://raw.githubusercontent.com/Microsoft/Cognitive-CustomVision-Windows/master/Samples/Images/Test/test_image.jpg" }' 56 | run(input_url) -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/main.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 time 6 | import os 7 | import sys 8 | import asyncio 9 | from six.moves import input 10 | import threading 11 | from azure.iot.device.aio import IoTHubModuleClient 12 | 13 | async def main(): 14 | try: 15 | if not sys.version >= "3.5.3": 16 | raise Exception( "The sample requires python 3.5.3+. Current version of Python: %s" % sys.version ) 17 | print ( "IoT Hub Client for Python" ) 18 | 19 | # The client object is used to interact with your Azure IoT hub. 20 | module_client = IoTHubModuleClient.create_from_edge_environment() 21 | 22 | # connect the client. 23 | await module_client.connect() 24 | 25 | # define behavior for receiving an input message on input1 26 | async def input1_listener(module_client): 27 | while True: 28 | input_message = await module_client.receive_message_on_input("input1") # blocking call 29 | print("the data in the message received on input1 was ") 30 | print(input_message.data) 31 | print("custom properties are") 32 | print(input_message.custom_properties) 33 | print("forwarding mesage to output1") 34 | await module_client.send_message_to_output(input_message, "output1") 35 | 36 | # define behavior for halting the application 37 | def stdin_listener(): 38 | while True: 39 | try: 40 | selection = input("Press Q to quit\n") 41 | if selection == "Q" or selection == "q": 42 | print("Quitting...") 43 | break 44 | except: 45 | time.sleep(10) 46 | 47 | # Schedule task for C2D Listener 48 | listeners = asyncio.gather(input1_listener(module_client)) 49 | 50 | print ( "The sample is now waiting for messages. ") 51 | 52 | # Run the stdin listener in the event loop 53 | loop = asyncio.get_event_loop() 54 | user_finished = loop.run_in_executor(None, stdin_listener) 55 | 56 | # Wait for user to indicate they are done listening for messages 57 | await user_finished 58 | 59 | # Cancel listening 60 | listeners.cancel() 61 | 62 | # Finally, disconnect 63 | await module_client.disconnect() 64 | 65 | except Exception as e: 66 | print ( "Unexpected error %s " % e ) 67 | raise 68 | 69 | if __name__ == "__main__": 70 | loop = asyncio.get_event_loop() 71 | loop.run_until_complete(main()) 72 | loop.close() 73 | 74 | # If using Python 3.7 or above, you can use following code instead: 75 | # asyncio.run(main()) -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-version": "0.0.1", 3 | "description": "", 4 | "image": { 5 | "repository": "partnercontainerregistry.azurecr.io/fruitclassifier", 6 | "tag": { 7 | "version": "0.0.1", 8 | "platforms": { 9 | "amd64": "./Dockerfile" 10 | } 11 | }, 12 | "buildOptions": [], 13 | "contextPath": "./" 14 | }, 15 | "language": "python" 16 | } -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/fruitclassifier/requirements.txt: -------------------------------------------------------------------------------- 1 | azure-iot-device~=2.0.0 -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/processingmodule/.dockerignore: -------------------------------------------------------------------------------- 1 | [b|B]in 2 | [O|o]bj -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/processingmodule/.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 | .vs 32 | 33 | [Bb]in/ 34 | [Oo]bj/ -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/processingmodule/Dockerfile.amd64: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build-env 2 | WORKDIR /app 3 | 4 | COPY *.csproj ./ 5 | RUN dotnet restore 6 | 7 | COPY . ./ 8 | RUN dotnet publish -c Release -o out 9 | 10 | FROM mcr.microsoft.com/dotnet/core/runtime:2.1-stretch-slim 11 | WORKDIR /app 12 | COPY --from=build-env /app/out ./ 13 | 14 | RUN useradd -ms /bin/bash moduleuser 15 | USER moduleuser 16 | 17 | ENTRYPOINT ["dotnet", "processingmodule.dll"] -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/processingmodule/Dockerfile.amd64.debug: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/runtime:2.1-stretch-slim AS base 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y --no-install-recommends unzip procps && \ 5 | rm -rf /var/lib/apt/lists/* 6 | 7 | RUN useradd -ms /bin/bash moduleuser 8 | USER moduleuser 9 | RUN curl -sSL https://aka.ms/getvsdbgsh | bash /dev/stdin -v latest -l ~/vsdbg 10 | 11 | FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build-env 12 | WORKDIR /app 13 | 14 | COPY *.csproj ./ 15 | RUN dotnet restore 16 | 17 | COPY . ./ 18 | RUN dotnet publish -c Debug -o out 19 | 20 | FROM base 21 | WORKDIR /app 22 | COPY --from=build-env /app/out ./ 23 | 24 | ENTRYPOINT ["dotnet", "processingmodule.dll"] -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/processingmodule/Logger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace processingmodule 7 | { 8 | /// 9 | /// This class is a stand in for a more robust logging system 10 | /// 11 | public class Logger 12 | { 13 | public static LogSeverity LoggingLevel = LogSeverity.Verbose; 14 | 15 | public static void Log(string message, LogSeverity severity = LogSeverity.Verbose) 16 | { 17 | if (severity <= Logger.LoggingLevel) 18 | { 19 | Console.WriteLine($"{severity.ToString("g")}:{message}"); 20 | } 21 | } 22 | } 23 | 24 | public enum LogSeverity { Error, Warning, Verbose } 25 | } -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/processingmodule/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-version": "0.0.1", 3 | "description": "Azure IoT edge processing module do process messages forwarded by proxy module then send the processed message back to proxy module. Proxy module will forward processed message over to the native Windows application.", 4 | "image": { 5 | "repository": "partnercontainerregistry.azurecr.io/processingmodule", 6 | "tag": { 7 | "version": "2.0.0", 8 | "platforms": { 9 | "amd64": "./Dockerfile.amd64", 10 | "amd64.debug": "./Dockerfile.amd64.debug" 11 | } 12 | }, 13 | "buildOptions": [], 14 | "contextPath": "./" 15 | }, 16 | "language": "csharp" 17 | } 18 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/processingmodule/processingmodule.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | netcoreapp2.1 5 | 6 | 7 | 8 | True 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/proxymodule/.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 | .vs 32 | 33 | [Bb]in/ 34 | [Oo]bj/ -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/proxymodule/Dockerfile.amd64: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build-env 2 | WORKDIR /app 3 | 4 | COPY *.csproj ./ 5 | RUN dotnet restore 6 | 7 | COPY . ./ 8 | RUN dotnet publish -c Release -o out 9 | 10 | FROM mcr.microsoft.com/dotnet/core/runtime:2.1-stretch-slim 11 | WORKDIR /app 12 | COPY --from=build-env /app/out ./ 13 | 14 | RUN useradd -ms /bin/bash moduleuser 15 | USER moduleuser 16 | 17 | ENTRYPOINT ["dotnet", "proxymodule.dll"] -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/proxymodule/Dockerfile.amd64.debug: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/runtime:2.1-stretch-slim AS base 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y --no-install-recommends unzip procps && \ 5 | rm -rf /var/lib/apt/lists/* 6 | 7 | RUN useradd -ms /bin/bash moduleuser 8 | USER moduleuser 9 | RUN curl -sSL https://aka.ms/getvsdbgsh | bash /dev/stdin -v latest -l ~/vsdbg 10 | 11 | FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build-env 12 | WORKDIR /app 13 | 14 | COPY *.csproj ./ 15 | RUN dotnet restore 16 | 17 | COPY . ./ 18 | RUN dotnet publish -c Debug -o out 19 | 20 | FROM base 21 | WORKDIR /app 22 | COPY --from=build-env /app/out ./ 23 | 24 | ENTRYPOINT ["dotnet", "proxymodule.dll"] -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/proxymodule/Logger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace proxymodule 7 | { 8 | /// 9 | /// This class is a stand in for a more robust logging system 10 | /// 11 | public class Logger 12 | { 13 | public static LogSeverity LoggingLevel = LogSeverity.Verbose; 14 | 15 | public static void Log(string message, LogSeverity severity = LogSeverity.Verbose) 16 | { 17 | if (severity <= Logger.LoggingLevel) 18 | { 19 | Console.WriteLine($"{severity.ToString("g")}:{message}"); 20 | } 21 | } 22 | } 23 | 24 | public enum LogSeverity { Error, Warning, Verbose } 25 | } -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/proxymodule/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-version": "0.0.1", 3 | "description": "Azure IoT edge Proxy module provides interoporability with a native Windows application.", 4 | "image": { 5 | "repository": "partnercontainerregistry.azurecr.io/proxymodule", 6 | "tag": { 7 | "version": "2.0.0", 8 | "platforms": { 9 | "amd64": "./Dockerfile.amd64", 10 | "amd64.debug": "./Dockerfile.amd64.debug" 11 | } 12 | }, 13 | "buildOptions": [], 14 | "contextPath": "./" 15 | }, 16 | "language": "csharp" 17 | } 18 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/customvision/modules/proxymodule/proxymodule.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | netcoreapp2.1 5 | 6 | 7 | 8 | True 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/.gitignore: -------------------------------------------------------------------------------- 1 | config/ 2 | .env 3 | LeafDeviceUWPApp/.vs/ 4 | LeafDeviceUWPApp/obj/ 5 | LeafDeviceUWPApp/bin/ -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/StoreLogo.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/CertificateManager.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.IO; 6 | using System.Security.Cryptography.X509Certificates; 7 | 8 | namespace LeafDeviceUWPApp 9 | { 10 | internal class CertificateManager 11 | { 12 | /// 13 | /// Add certificate in local cert store for use by downstream device 14 | /// client for secure connection to IoT Edge runtime. 15 | /// 16 | /// Note: On Windows machines, if you have not run this from an Administrator prompt, 17 | /// a prompt will likely come up to confirm the installation of the certificate. 18 | /// This usually happens the first time a certificate will be installed. 19 | /// 20 | public static void InstallCACert(string certificatePath) 21 | { 22 | if (string.IsNullOrWhiteSpace(certificatePath)) 23 | { 24 | throw new ArgumentNullException(nameof(certificatePath)); 25 | } 26 | 27 | Console.WriteLine($"User configured CA certificate path: {certificatePath}"); 28 | if (!File.Exists(certificatePath)) 29 | { 30 | // cannot proceed further without a proper cert file 31 | Console.WriteLine($"Invalid certificate file: {certificatePath}"); 32 | throw new InvalidOperationException("Invalid certificate file."); 33 | } 34 | else 35 | { 36 | Console.WriteLine($"Attempting to install CA certificate: {certificatePath}"); 37 | var store = new X509Store(StoreName.Root, StoreLocation.CurrentUser); 38 | store.Open(OpenFlags.ReadWrite); 39 | store.Add(new X509Certificate2(X509Certificate2.CreateFromCertFile(certificatePath))); 40 | Console.WriteLine($"Successfully added certificate: {certificatePath}"); 41 | store.Close(); 42 | } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/LeafDeviceUWPApp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29728.190 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LeafDeviceUWPApp", "LeafDeviceUWPApp.csproj", "{53F49575-5660-43E8-AA48-2E23D60C6153}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|ARM64 = Debug|ARM64 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|ARM = Release|ARM 15 | Release|ARM64 = Release|ARM64 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|ARM.ActiveCfg = Debug|ARM 21 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|ARM.Build.0 = Debug|ARM 22 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|ARM.Deploy.0 = Debug|ARM 23 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|ARM64.ActiveCfg = Debug|ARM64 24 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|ARM64.Build.0 = Debug|ARM64 25 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|ARM64.Deploy.0 = Debug|ARM64 26 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|x64.ActiveCfg = Debug|x64 27 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|x64.Build.0 = Debug|x64 28 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|x64.Deploy.0 = Debug|x64 29 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|x86.ActiveCfg = Debug|x86 30 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|x86.Build.0 = Debug|x86 31 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Debug|x86.Deploy.0 = Debug|x86 32 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|ARM.ActiveCfg = Release|ARM 33 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|ARM.Build.0 = Release|ARM 34 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|ARM.Deploy.0 = Release|ARM 35 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|ARM64.ActiveCfg = Release|ARM64 36 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|ARM64.Build.0 = Release|ARM64 37 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|ARM64.Deploy.0 = Release|ARM64 38 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|x64.ActiveCfg = Release|x64 39 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|x64.Build.0 = Release|x64 40 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|x64.Deploy.0 = Release|x64 41 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|x86.ActiveCfg = Release|x86 42 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|x86.Build.0 = Release|x86 43 | {53F49575-5660-43E8-AA48-2E23D60C6153}.Release|x86.Deploy.0 = Release|x86 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {5C42CFBB-B39B-4888-BEAF-A2E7B61A5FC9} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | LeafDeviceUWPApp 19 | mdatla 20 | Assets\StoreLogo.png 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 35 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Reflection; 5 | using System.Runtime.CompilerServices; 6 | using System.Runtime.InteropServices; 7 | 8 | // General Information about an assembly is controlled through the following 9 | // set of attributes. Change these attribute values to modify the information 10 | // associated with an assembly. 11 | [assembly: AssemblyTitle("LeafDeviceUWPApp")] 12 | [assembly: AssemblyDescription("LeafDeviceUWPApp is a sample UWP application to demonstrate interop with IoT edge module.")] 13 | [assembly: AssemblyConfiguration("")] 14 | [assembly: AssemblyCompany("Microsoft Corporation")] 15 | [assembly: AssemblyProduct("Azure IoT edge on Linux for Windows")] 16 | [assembly: AssemblyCopyright("Copyright © Microsoft Corporation")] 17 | [assembly: AssemblyTrademark("")] 18 | [assembly: AssemblyCulture("")] 19 | 20 | // Version information for an assembly consists of the following four values: 21 | // 22 | // Major Version 23 | // Minor Version 24 | // Build Number 25 | // Revision 26 | // 27 | // You can specify all the values or you can default the Build and Revision Numbers 28 | // by using the '*' as shown below: 29 | // [assembly: AssemblyVersion("1.0.*")] 30 | [assembly: AssemblyVersion("1.0.0.0")] 31 | [assembly: AssemblyFileVersion("1.0.0.0")] 32 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/LeafDeviceUWPApp/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/deployment.debug.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-template": "2.0.0", 3 | "modulesContent": { 4 | "$edgeAgent": { 5 | "properties.desired": { 6 | "schemaVersion": "1.0", 7 | "runtime": { 8 | "type": "docker", 9 | "settings": { 10 | "minDockerVersion": "v1.25", 11 | "loggingOptions": "", 12 | "registryCredentials": { 13 | "partnercontainerregistry": { 14 | "username": "$CONTAINER_REGISTRY_USERNAME_partnercontainerregistry", 15 | "password": "$CONTAINER_REGISTRY_PASSWORD_partnercontainerregistry", 16 | "address": "partnercontainerregistry.azurecr.io" 17 | } 18 | } 19 | } 20 | }, 21 | "systemModules": { 22 | "edgeAgent": { 23 | "type": "docker", 24 | "settings": { 25 | "image": "mcr.microsoft.com/azureiotedge-agent:1.0", 26 | "createOptions": {} 27 | } 28 | }, 29 | "edgeHub": { 30 | "type": "docker", 31 | "status": "running", 32 | "restartPolicy": "always", 33 | "settings": { 34 | "image": "mcr.microsoft.com/azureiotedge-hub:1.0", 35 | "createOptions": { 36 | "HostConfig": { 37 | "PortBindings": { 38 | "5671/tcp": [ 39 | { 40 | "HostPort": "5671" 41 | } 42 | ], 43 | "8883/tcp": [ 44 | { 45 | "HostPort": "8883" 46 | } 47 | ], 48 | "443/tcp": [ 49 | { 50 | "HostPort": "443" 51 | } 52 | ] 53 | } 54 | } 55 | } 56 | } 57 | } 58 | }, 59 | "modules": { 60 | "proxymodule": { 61 | "version": "1.0", 62 | "type": "docker", 63 | "status": "running", 64 | "restartPolicy": "always", 65 | "settings": { 66 | "image": "${MODULES.proxymodule.debug}", 67 | "createOptions": {} 68 | } 69 | }, 70 | "processingmodule": { 71 | "version": "1.0", 72 | "type": "docker", 73 | "status": "running", 74 | "restartPolicy": "always", 75 | "settings": { 76 | "image": "${MODULES.processingmodule.debug}", 77 | "createOptions": {} 78 | } 79 | } 80 | } 81 | } 82 | }, 83 | "$edgeHub": { 84 | "properties.desired": { 85 | "schemaVersion": "1.0", 86 | "routes": { 87 | "leafdevicetoproxymoduleroute": "FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO BrokeredEndpoint(\"/modules/proxymodule/inputs/leafdeviceinput\")", 88 | "proxymoduletoprocessingmoduleroute": "FROM /messages/modules/proxymodule/outputs/processingoutput INTO BrokeredEndpoint(\"/modules/processingmodule/inputs/datainput\")", 89 | "processingmoduletoproxymoduleroute": "FROM/messages/modules/processingmodule/outputs/resultoutput INTO BrokeredEndpoint(\"/modules/proxymodule/inputs/resultinput\")", 90 | "proxymoduletocloud": "FROM /messages/modules/proxymodule/outputs/cloudmessage INTO $upstream" 91 | }, 92 | "storeAndForwardConfiguration": { 93 | "timeToLiveSecs": 7200 94 | } 95 | } 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/deployment.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-template": "2.0.0", 3 | "modulesContent": { 4 | "$edgeAgent": { 5 | "properties.desired": { 6 | "schemaVersion": "1.0", 7 | "runtime": { 8 | "type": "docker", 9 | "settings": { 10 | "minDockerVersion": "v1.25", 11 | "loggingOptions": "", 12 | "registryCredentials": { 13 | "partnercontainerregistry": { 14 | "username": "$CONTAINER_REGISTRY_USERNAME_partnercontainerregistry", 15 | "password": "$CONTAINER_REGISTRY_PASSWORD_partnercontainerregistry", 16 | "address": "partnercontainerregistry.azurecr.io" 17 | } 18 | } 19 | } 20 | }, 21 | "systemModules": { 22 | "edgeAgent": { 23 | "type": "docker", 24 | "settings": { 25 | "image": "mcr.microsoft.com/azureiotedge-agent:1.0", 26 | "createOptions": {} 27 | } 28 | }, 29 | "edgeHub": { 30 | "type": "docker", 31 | "status": "running", 32 | "restartPolicy": "always", 33 | "settings": { 34 | "image": "mcr.microsoft.com/azureiotedge-hub:1.0", 35 | "createOptions": { 36 | "HostConfig": { 37 | "PortBindings": { 38 | "5671/tcp": [ 39 | { 40 | "HostPort": "5671" 41 | } 42 | ], 43 | "8883/tcp": [ 44 | { 45 | "HostPort": "8883" 46 | } 47 | ], 48 | "443/tcp": [ 49 | { 50 | "HostPort": "443" 51 | } 52 | ] 53 | } 54 | } 55 | } 56 | } 57 | } 58 | }, 59 | "modules": { 60 | "proxymodule": { 61 | "version": "1.0", 62 | "type": "docker", 63 | "status": "running", 64 | "restartPolicy": "always", 65 | "settings": { 66 | "image": "${MODULES.proxymodule}", 67 | "createOptions": {} 68 | } 69 | }, 70 | "processingmodule": { 71 | "version": "1.0", 72 | "type": "docker", 73 | "status": "running", 74 | "restartPolicy": "always", 75 | "settings": { 76 | "image": "${MODULES.processingmodule}", 77 | "createOptions": {} 78 | } 79 | } 80 | } 81 | } 82 | }, 83 | "$edgeHub": { 84 | "properties.desired": { 85 | "schemaVersion": "1.0", 86 | "routes": { 87 | "leafdevicetoproxymoduleroute": "FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO BrokeredEndpoint(\"/modules/proxymodule/inputs/leafdeviceinput\")", 88 | "proxymoduletoprocessingmoduleroute": "FROM /messages/modules/proxymodule/outputs/processingoutput INTO BrokeredEndpoint(\"/modules/processingmodule/inputs/datainput\")", 89 | "processingmoduletoproxymoduleroute": "FROM/messages/modules/processingmodule/outputs/resultoutput INTO BrokeredEndpoint(\"/modules/proxymodule/inputs/resultinput\")", 90 | "proxymoduletocloud": "FROM /messages/modules/proxymodule/outputs/cloudmessage INTO $upstream" 91 | }, 92 | "storeAndForwardConfiguration": { 93 | "timeToLiveSecs": 7200 94 | } 95 | } 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/processingmodule/.dockerignore: -------------------------------------------------------------------------------- 1 | [b|B]in 2 | [O|o]bj -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/processingmodule/.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 | .vs 32 | 33 | [Bb]in/ 34 | [Oo]bj/ -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/processingmodule/Dockerfile.amd64: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build-env 2 | WORKDIR /app 3 | 4 | COPY *.csproj ./ 5 | RUN dotnet restore 6 | 7 | COPY . ./ 8 | RUN dotnet publish -c Release -o out 9 | 10 | FROM mcr.microsoft.com/dotnet/core/runtime:2.1-stretch-slim 11 | WORKDIR /app 12 | COPY --from=build-env /app/out ./ 13 | 14 | RUN useradd -ms /bin/bash moduleuser 15 | USER moduleuser 16 | 17 | ENTRYPOINT ["dotnet", "processingmodule.dll"] -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/processingmodule/Dockerfile.amd64.debug: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/runtime:2.1-stretch-slim AS base 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y --no-install-recommends unzip procps && \ 5 | rm -rf /var/lib/apt/lists/* 6 | 7 | RUN useradd -ms /bin/bash moduleuser 8 | USER moduleuser 9 | RUN curl -sSL https://aka.ms/getvsdbgsh | bash /dev/stdin -v latest -l ~/vsdbg 10 | 11 | FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build-env 12 | WORKDIR /app 13 | 14 | COPY *.csproj ./ 15 | RUN dotnet restore 16 | 17 | COPY . ./ 18 | RUN dotnet publish -c Debug -o out 19 | 20 | FROM base 21 | WORKDIR /app 22 | COPY --from=build-env /app/out ./ 23 | 24 | ENTRYPOINT ["dotnet", "processingmodule.dll"] -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/processingmodule/Logger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace processingmodule 7 | { 8 | /// 9 | /// This class is a stand in for a more robust logging system 10 | /// 11 | public class Logger 12 | { 13 | public static LogSeverity LoggingLevel = LogSeverity.Verbose; 14 | 15 | public static void Log(string message, LogSeverity severity = LogSeverity.Verbose) 16 | { 17 | if (severity <= Logger.LoggingLevel) 18 | { 19 | Console.WriteLine($"{severity.ToString("g")}:{message}"); 20 | } 21 | } 22 | } 23 | 24 | public enum LogSeverity { Error, Warning, Verbose } 25 | } -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/processingmodule/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-version": "0.0.1", 3 | "description": "Azure IoT edge processing module do process messages forwarded by proxy module then send the processed message back to proxy module. Proxy module will forward processed message over to the native Windows application.", 4 | "image": { 5 | "repository": "partnercontainerregistry.azurecr.io/processingmodule", 6 | "tag": { 7 | "version": "1.0.0", 8 | "platforms": { 9 | "amd64": "./Dockerfile.amd64", 10 | "amd64.debug": "./Dockerfile.amd64.debug" 11 | } 12 | }, 13 | "buildOptions": [], 14 | "contextPath": "./" 15 | }, 16 | "language": "csharp" 17 | } 18 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/processingmodule/processingmodule.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | netcoreapp2.1 5 | 6 | 7 | 8 | True 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/proxymodule/.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 | .vs 32 | 33 | [Bb]in/ 34 | [Oo]bj/ -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/proxymodule/Dockerfile.amd64: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build-env 2 | WORKDIR /app 3 | 4 | COPY *.csproj ./ 5 | RUN dotnet restore 6 | 7 | COPY . ./ 8 | RUN dotnet publish -c Release -o out 9 | 10 | FROM mcr.microsoft.com/dotnet/core/runtime:2.1-stretch-slim 11 | WORKDIR /app 12 | COPY --from=build-env /app/out ./ 13 | 14 | RUN useradd -ms /bin/bash moduleuser 15 | USER moduleuser 16 | 17 | ENTRYPOINT ["dotnet", "proxymodule.dll"] -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/proxymodule/Dockerfile.amd64.debug: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/runtime:2.1-stretch-slim AS base 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y --no-install-recommends unzip procps && \ 5 | rm -rf /var/lib/apt/lists/* 6 | 7 | RUN useradd -ms /bin/bash moduleuser 8 | USER moduleuser 9 | RUN curl -sSL https://aka.ms/getvsdbgsh | bash /dev/stdin -v latest -l ~/vsdbg 10 | 11 | FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build-env 12 | WORKDIR /app 13 | 14 | COPY *.csproj ./ 15 | RUN dotnet restore 16 | 17 | COPY . ./ 18 | RUN dotnet publish -c Debug -o out 19 | 20 | FROM base 21 | WORKDIR /app 22 | COPY --from=build-env /app/out ./ 23 | 24 | ENTRYPOINT ["dotnet", "proxymodule.dll"] -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/proxymodule/Logger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace proxymodule 7 | { 8 | /// 9 | /// This class is a stand in for a more robust logging system 10 | /// 11 | public class Logger 12 | { 13 | public static LogSeverity LoggingLevel = LogSeverity.Verbose; 14 | 15 | public static void Log(string message, LogSeverity severity = LogSeverity.Verbose) 16 | { 17 | if (severity <= Logger.LoggingLevel) 18 | { 19 | Console.WriteLine($"{severity.ToString("g")}:{message}"); 20 | } 21 | } 22 | } 23 | 24 | public enum LogSeverity { Error, Warning, Verbose } 25 | } -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/proxymodule/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-version": "0.0.1", 3 | "description": "Azure IoT edge Proxy module provides interoporability with a native Windows application.", 4 | "image": { 5 | "repository": "partnercontainerregistry.azurecr.io/proxymodule", 6 | "tag": { 7 | "version": "1.0.0", 8 | "platforms": { 9 | "amd64": "./Dockerfile.amd64", 10 | "amd64.debug": "./Dockerfile.amd64.debug" 11 | } 12 | }, 13 | "buildOptions": [], 14 | "contextPath": "./" 15 | }, 16 | "language": "csharp" 17 | } 18 | -------------------------------------------------------------------------------- /samples/interop-customvision-textmsg-uwpapp/textmsg-uwpapp/modules/proxymodule/proxymodule.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | netcoreapp2.1 5 | 6 | 7 | 8 | True 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Create Certificates for Authentication.MD: -------------------------------------------------------------------------------- 1 | # Interop Console App with Linux Edge Module 2 | ## Progress 3 | 4 | - [x] [Introduction](../README.md) 5 | - [x] [Step 1 - Setup Azure Resources](./Setup%20Azure%20Resources.MD) 6 | - [x] [Step 2 - Setup Azure IoT Edge for Linux on Windows](./Setup%20Azure%20IoT%20Edge%20for%20Linux%20on%20Windows.MD) 7 | - [x] [Step 3 - Develop and publish the IoT Edge Linux module](./Develop%20and%20publish%20the%20IoT%20edge%20Linux%20module.MD) 8 | - [ ] **Step 4 - Create Certificates for Authentication** 9 | - [ ] [Step 5 - Develop the Windows C# Console Application](./Develop%20the%20Windows%20C%23%20Console%20Application.MD) 10 | - [ ] [Step 6 - Configuring the IoT Edge Device](./Configuring%20the%20IoT%20Edge%20Device.MD) 11 | - [ ] [Step 7 - Deploy the Modules onto the IoT Edge Device](./Deploy%20the%20Modules%20onto%20the%20IoT%20Edge%20Device.MD) 12 | - [ ] [Step 8 - Run the Console Application](./Run%20the%20Console%20Application.MD) 13 | - [ ] [Troubleshooting](./Troubleshooting.MD) 14 | --- 15 | # Step 4: Create Certificates for Authentication 16 | This part describes the relevant steps to create sample certificates for the authentication between downstream device and IoT edge. 17 | 18 | * **To create a sample PKI with certificate validity for one month** 19 | Complete the steps within the steps of [Create demo certificates to test IoT Edge device features](https://learn.microsoft.com/en-us/azure/iot-edge/how-to-create-transparent-gateway?view=iotedge-1.4&tabs=eflow#create-demo-certificates). 20 | 21 | * **To generate customizable test certificates** 22 | Follow the steps described in [Generate test certificates for Edge Gateway](https://github.com/Azure-Samples/IoTEdgeAndMlSample/tree/master/CreateCertificates) to create sample certificates to use for the interop solution. It generates certificates with default subject name "turbofanGateway" and 30 days validity. To extend the validity of certificates (or) to change the subject name, make the following modifications to **dockerfile** then re-build the docker image. 23 | 24 | You can also use your own root CA certificate in case you have a (test) PKI for downstream devices and edge devices. In any of the two latter cases, replace the private key, certificate chain, and root CA cert. 25 | 26 | Go to [Next Step](./Develop%20the%20Windows%20C%23%20Console%20Application.MD) 27 | -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Deploy the Modules onto the IoT Edge Device.MD: -------------------------------------------------------------------------------- 1 | # Interop Console App with Linux Edge Module 2 | ## Progress 3 | 4 | - [x] [Introduction](../README.md) 5 | - [x] [Step 1 - Setup Azure Resources](./Setup%20Azure%20Resources.MD) 6 | - [x] [Step 2 - Setup Azure IoT Edge for Linux on Windows](./Setup%20Azure%20IoT%20Edge%20for%20Linux%20on%20Windows.MD) 7 | - [x] [Step 3 - Develop and publish the IoT Edge Linux module](./Develop%20and%20publish%20the%20IoT%20edge%20Linux%20module.MD) 8 | - [x] [Step 4 - Create Certificates for Authentication](./Create%20Certificates%20for%20Authentication.MD) 9 | - [x] [Step 5 - Develop the Windows C# Console Application](./Develop%20the%20Windows%20C%23%20Console%20Application.MD) 10 | - [x] [Step 6 - Configuring the IoT Edge Device](./Configuring%20the%20IoT%20Edge%20Device.MD) 11 | - [ ] **Step 7 - Deploy the Modules onto the IoT Edge Device** 12 | - [ ] [Troubleshooting](./Troubleshooting.MD) 13 | --- 14 | 15 | # Step 7: Deploy the Modules onto the IoT Edge Device 16 | Having the IoT Edge device set up, we now deploy the Linux modules onto the device. 17 | 18 | ## Steps in the development VM 19 | 20 | 1. Perform the following steps from **Deploy Azure IoT Edge modules from Visual Studio Code** documentation. 21 | * [Sign in to access your IoT Hub](https://docs.microsoft.com/azure/iot-edge/how-to-deploy-modules-vscode#sign-in-to-access-your-iot-hub) 22 | * [Deploy to your device](https://docs.microsoft.com/azure/iot-edge/how-to-deploy-modules-vscode#deploy-to-your-device) 23 | (Select the file **deployment.amd64.json** from the **config** folder as manifest file to be deployed.) 24 | 25 | * [View modules on your device](https://docs.microsoft.com/azure/iot-edge/how-to-deploy-modules-vscode#view-modules-on-your-device) 26 | 27 | ## Steps in the Linux environment of the IoT Edge Device 28 | Using the Linux command shell that you signed into in [Step 6.2](./Configuring%20the%20IoT%20Edge%20Device.MD), run the following command to see the modules that have been deployed to your edge device. 29 | ```powershell 30 | sudo iotedge list 31 | ``` 32 | 33 | You should see the CSharpModule like the following: 34 | 35 | ![Console Application](./Images/IoTEdgeList.png) 36 | 37 | 38 | Go to [Next Step](./Run%20the%20Console%20Application.MD) 39 | -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Images/BuildAndPushError.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-textmsg-consoleapp/Documentation/Images/BuildAndPushError.png -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Images/ConsoleAppRunning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-textmsg-consoleapp/Documentation/Images/ConsoleAppRunning.png -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Images/IoTEdgeList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-textmsg-consoleapp/Documentation/Images/IoTEdgeList.png -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Images/IoTEdgeLogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-textmsg-consoleapp/Documentation/Images/IoTEdgeLogs.png -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Images/LogError.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-textmsg-consoleapp/Documentation/Images/LogError.png -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Images/MicrosoftCert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-textmsg-consoleapp/Documentation/Images/MicrosoftCert.png -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Images/Resolvctl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-textmsg-consoleapp/Documentation/Images/Resolvctl.png -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Images/TLS_Error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/iotedge-eflow/7f09e2b15378600939906bcc4be4441106158cf8/samples/interop-textmsg-consoleapp/Documentation/Images/TLS_Error.png -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Run the Console Application.MD: -------------------------------------------------------------------------------- 1 | # Interop Console App with Linux Edge Module 2 | ## Progress 3 | 4 | - [x] [Introduction](../README.md) 5 | - [x] [Step 1 - Setup Azure Resources](./Setup%20Azure%20Resources.MD) 6 | - [x] [Step 2 - Setup Azure IoT Edge for Linux on Windows](./Setup%20Azure%20IoT%20Edge%20for%20Linux%20on%20Windows.MD) 7 | - [x] [Step 3 - Develop and publish the IoT Edge Linux module](./Develop%20and%20publish%20the%20IoT%20edge%20Linux%20module.MD) 8 | - [x] [Step 4 - Create Certificates for Authentication](./Create%20Certificates%20for%20Authentication.MD) 9 | - [x] [Step 5 - Develop the Windows C# Console Application](./Develop%20the%20Windows%20C%23%20Console%20Application.MD) 10 | - [x] [Step 6 - Configuring the IoT Edge Device](./Configuring%20the%20IoT%20Edge%20Device.MD) 11 | - [x] [Step 7 - Deploy the Modules onto the IoT Edge Device](./Deploy%20the%20Modules%20onto%20the%20IoT%20Edge%20Device.MD) 12 | - [ ] **Step 8 - Run the Console Application** 13 | - [ ] [Troubleshooting](./Troubleshooting.MD) 14 | --- 15 | 16 | # Step 8: Run the Console Application 17 | We now deploy the Windows application onto the IoT device and run it to let it interoperate with the Linux modules. 18 | 19 | 1. Change into the console application package folder previously copied to the Windows IoT device. 20 | 2. Run the console application on the command prompt by running the below command. 21 | ```powershell 22 | .\LeafDeviceApp.exe -x "" -g "" -c "" 23 | ``` 24 | Press 1 to send a message to the Linux module. 25 | 26 | You shoud see something like the following: 27 | 28 | ![Console Application](./Images/ConsoleAppRunning.png) 29 | 1. Run the below command to see the edge logs 30 | ```bash 31 | sudo iotedge logs SampleModule 32 | ``` 33 | You should see something like the following: 34 | ![Console Application](./Images/IoTEdgeLogs.png) 35 | 36 | Go to [Next Step](./Troubleshooting.MD) 37 | -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Setup Azure IoT Edge for Linux on Windows.MD: -------------------------------------------------------------------------------- 1 | # Interop Console App with Linux Edge Module 2 | ## Progress 3 | 4 | - [x] [Introduction](../README.md) 5 | - [x] [Step 1 - Setup Azure Resources](./Setup%20Azure%20Resources.MD) 6 | - [ ] **Step 2 - Setup Azure IoT Edge for Linux on Windows** 7 | - [ ] [Step 3 - Develop and publish the IoT Edge Linux module](./Develop%20and%20publish%20the%20IoT%20edge%20Linux%20module.MD) 8 | - [ ] [Step 4 - Create Certificates for Authentication](./Create%20Certificates%20for%20Authentication.MD) 9 | - [ ] [Step 5 - Develop the Windows C# Console Application](./Develop%20the%20Windows%20C%23%20Console%20Application.MD) 10 | - [ ] [Step 6 - Configuring the IoT Edge Device](./Configuring%20the%20IoT%20Edge%20Device.MD) 11 | - [ ] [Step 7 - Deploy the Modules onto the IoT Edge Device](./Deploy%20the%20Modules%20onto%20the%20IoT%20Edge%20Device.MD) 12 | - [ ] [Step 8 - Run the Console Application](./Run%20the%20Console%20Application.MD) 13 | - [ ] [Troubleshooting](./Troubleshooting.MD) 14 | --- 15 | # Step 2: Setup Azure IoT Edge for Linux on Windows 16 | This part describes the relevant steps to setup Azure IoT Edge for Linux on Winows (EFLOW). 17 | 18 | * **To create a EFLOW device** 19 | Complete the steps described in [Install and provision Azure IoT Edge for Linux on a Windows device](https://docs.microsoft.com/azure/iot-edge/how-to-install-iot-edge-on-windows) guide. 20 | 21 | * **To learn more about EFLOW** 22 | For more information, review [EFLOW docs](https://docs.microsoft.com/azure/iot-edge/iot-edge-for-linux-on-windows). 23 | 24 | 25 | Go to [Next Step](./Develop%20and%20publish%20the%20IoT%20edge%20Linux%20module.MD) 26 | -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/Documentation/Troubleshooting.MD: -------------------------------------------------------------------------------- 1 | ## Troubleshooting 2 | 3 | ## Progress 4 | 5 | - [x] [Introduction](../README.md) 6 | - [x] [Step 1 - Setup Azure Resources](./Setup%20Azure%20Resources.MD) 7 | - [x] [Step 2 - Setup Azure IoT Edge for Linux on Windows](./Setup%20Azure%20IoT%20Edge%20for%20Linux%20on%20Windows.MD) 8 | - [x] [Step 3 - Develop and publish the IoT Edge Linux module](./Develop%20and%20publish%20the%20IoT%20edge%20Linux%20module.MD) 9 | - [x] [Step 4 - Create Certificates for Authentication](./Create%20Certificates%20for%20Authentication.MD) 10 | - [x] [Step 5 - Develop the Windows C# Console Application](./Develop%20the%20Windows%20C%23%20Console%20Application.MD) 11 | - [x] [Step 6 - Configuring the IoT Edge Device](./Configuring%20the%20IoT%20Edge%20Device.MD) 12 | - [x] [Step 7 - Deploy the Modules onto the IoT Edge Device](./Deploy%20the%20Modules%20onto%20the%20IoT%20Edge%20Device.MD) 13 | - [x] [Step 8 - Run the Console Application](./Run%20the%20Console%20Application.MD) 14 | - [ ] **Troubleshooting** 15 | --- 16 | 17 | 18 | #### 1. Console message app shows TLS Error #### 19 | This problem is usually caused by a gateway issue. On the IoT Edge device configuration (/etc/iotedge/config.yaml) there's a section called hostname. This automatically gets populated with the system hostname. In some cases, hostname is not found and the user will have to use the EFLOW VM IP. Ensure the gateway name in the C# Windows app matches the hostname in the IoT Edge config.yaml. 20 | 21 | ![TLS Error](./Images/TLS_Error.png) 22 | 23 | If the previous steps doesn't work, follow these steps: 24 | 1. In the config.yaml, change the hostname to the IP address of the EFLOW VM. 25 | 2. `sudo systemctl restart aziot*` 26 | 3. `sudo systemctl status aziot*` - Make sure it says active (running) 27 | 4. `sudo iotedge check` 28 | 5. Run the c# console app using the IP address for the gateway address insted of the hostname 29 |
30 | 31 | 32 | > **Note:** You might get an error related to "correct hostname"; however the IoT Edge shoudl work correctly anyway 33 | > ![LogError](./Images/LogError.png) 34 | 35 | 36 | #### 2. Error when pushing a module to Azure Contianer Registry #### 37 | To fix an error when pushing the container, ensure that the module.json has the proper registry and container name appended: .azurecr.io/. For more information, visit [Can't Push IoT Edge module to Azure Container Registry](https://github.com/MicrosoftDocs/azure-docs/issues/22296). 38 |

39 | 40 | #### 3. Error when pushing a deploying the CSharpModule app #### 41 | To fix this error, change InteropSampleRegistry value in the registry credentials to direct values or add a separate environment variable for the registry container. 42 |

43 | 44 | #### 4. Operation is not valid due to the current state of the object in microsoft.azure.amqp #### 45 | This is a bug in AMQP and .NET 5. For more information about this error, check this [thread](https://stackoverflow.com/questions/64804036/operation-is-not-valid-due-to-the-current-state-of-the-object-source-microsoft). The solution is adding AMQP version requirement, as well as using .NET Core 3.1LTS instead of .NET 5 46 | ```csharp 47 | 48 | ``` 49 |
50 | 51 | #### 5. Modules not showing up in the IoT Edge device #### 52 | This error is generally related to an authentication issue when pulling the module from the container registryl. For further information, use the IoTEdge logs. 53 | ```powershell 54 | sudo iotedge logs edgeAgent 55 | sudo iotedge logs edgeHub 56 | ``` 57 | -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/LeafDeviceApp/CertificateManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Security.Cryptography.X509Certificates; 4 | 5 | namespace LeafDeviceApp 6 | { 7 | internal class CertificateManager 8 | { 9 | /// 10 | /// Add certificate in local cert store for use by downstream device 11 | /// client for secure connection to IoT Edge runtime. 12 | /// 13 | /// Note: On Windows machines, if you have not run this from an Administrator prompt, 14 | /// a prompt will likely come up to confirm the installation of the certificate. 15 | /// This usually happens the first time a certificate will be installed. 16 | /// 17 | public static void InstallCACert(string certificatePath) 18 | { 19 | if (string.IsNullOrWhiteSpace(certificatePath)) 20 | { 21 | throw new ArgumentNullException(nameof(certificatePath)); 22 | } 23 | 24 | Console.WriteLine($"User configured CA certificate path: {certificatePath}"); 25 | if (!File.Exists(certificatePath)) 26 | { 27 | // cannot proceed further without a proper cert file 28 | Console.WriteLine($"Invalid certificate file: {certificatePath}"); 29 | throw new InvalidOperationException("Invalid certificate file."); 30 | } 31 | else 32 | { 33 | Console.WriteLine($"Attempting to install CA certificate: {certificatePath}"); 34 | var store = new X509Store(StoreName.Root, StoreLocation.CurrentUser); 35 | store.Open(OpenFlags.ReadWrite); 36 | store.Add(new X509Certificate2(X509Certificate2.CreateFromCertFile(certificatePath))); 37 | Console.WriteLine($"Successfully added certificate: {certificatePath}"); 38 | store.Close(); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/LeafDeviceApp/LeafDeviceApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/deployment.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-template": "2.0.0", 3 | "modulesContent": { 4 | "$edgeAgent": { 5 | "properties.desired": { 6 | "schemaVersion": "1.0", 7 | "runtime": { 8 | "type": "docker", 9 | "settings": { 10 | "minDockerVersion": "v1.25", 11 | "loggingOptions": "", 12 | "registryCredentials": { 13 | "partnercontainerregistry": { 14 | "username": "$CONTAINER_REGISTRY_USERNAME_partnercontainerregistry", 15 | "password": "$CONTAINER_REGISTRY_PASSWORD_partnercontainerregistry", 16 | "address": "partnercontainerregistry.azurecr.io" 17 | } 18 | } 19 | } 20 | }, 21 | "systemModules": { 22 | "edgeAgent": { 23 | "type": "docker", 24 | "settings": { 25 | "image": "mcr.microsoft.com/azureiotedge-agent:1.0", 26 | "createOptions": {} 27 | } 28 | }, 29 | "edgeHub": { 30 | "type": "docker", 31 | "status": "running", 32 | "restartPolicy": "always", 33 | "settings": { 34 | "image": "mcr.microsoft.com/azureiotedge-hub:1.0", 35 | "createOptions": { 36 | "HostConfig": { 37 | "PortBindings": { 38 | "5671/tcp": [ 39 | { 40 | "HostPort": "5671" 41 | } 42 | ], 43 | "8883/tcp": [ 44 | { 45 | "HostPort": "8883" 46 | } 47 | ], 48 | "443/tcp": [ 49 | { 50 | "HostPort": "443" 51 | } 52 | ] 53 | } 54 | } 55 | } 56 | } 57 | } 58 | }, 59 | "modules": { 60 | "CSharpModule": { 61 | "version": "1.0", 62 | "type": "docker", 63 | "status": "running", 64 | "restartPolicy": "always", 65 | "settings": { 66 | "image": "${MODULES.CSharpModule}", 67 | "createOptions": {} 68 | } 69 | } 70 | } 71 | } 72 | }, 73 | "$edgeHub": { 74 | "properties.desired": { 75 | "schemaVersion": "1.0", 76 | "routes": { 77 | "leafdeviceinputendpoint": "FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO BrokeredEndpoint(\"/modules/CSharpModule/inputs/leafdeviceinput\")" 78 | }, 79 | "storeAndForwardConfiguration": { 80 | "timeToLiveSecs": 7200 81 | } 82 | } 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/modules/CSharpModule/CSharpModule.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | netcoreapp3.1 5 | 6 | 7 | 8 | True 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/modules/CSharpModule/Dockerfile.amd64: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build-env 2 | WORKDIR /app 3 | 4 | COPY *.csproj ./ 5 | RUN dotnet restore 6 | 7 | COPY . ./ 8 | RUN dotnet publish -c Release -o out 9 | 10 | FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim 11 | WORKDIR /app 12 | COPY --from=build-env /app/out ./ 13 | 14 | RUN useradd -ms /bin/bash moduleuser 15 | USER moduleuser 16 | 17 | ENTRYPOINT ["dotnet", "CSharpModule.dll"] -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/modules/CSharpModule/Dockerfile.amd64.debug: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim AS base 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y --no-install-recommends unzip procps && \ 5 | rm -rf /var/lib/apt/lists/* 6 | 7 | RUN useradd -ms /bin/bash moduleuser 8 | USER moduleuser 9 | RUN curl -sSL https://aka.ms/getvsdbgsh | bash /dev/stdin -v latest -l ~/vsdbg 10 | 11 | FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build-env 12 | WORKDIR /app 13 | 14 | COPY *.csproj ./ 15 | RUN dotnet restore 16 | 17 | COPY . ./ 18 | RUN dotnet publish -c Debug -o out 19 | 20 | FROM base 21 | WORKDIR /app 22 | COPY --from=build-env /app/out ./ 23 | 24 | ENTRYPOINT ["dotnet", "CSharpModule.dll"] -------------------------------------------------------------------------------- /samples/interop-textmsg-consoleapp/modules/CSharpModule/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema-version": "0.0.1", 3 | "description": "", 4 | "image": { 5 | "repository": "partnercontainerregistry.azurecr.io/csharpmodule", 6 | "tag": { 7 | "version": "0.0.1", 8 | "platforms": { 9 | "amd64": "./Dockerfile.amd64", 10 | "amd64.debug": "./Dockerfile.amd64.debug" 11 | } 12 | }, 13 | "buildOptions": [], 14 | "contextPath": "./" 15 | }, 16 | "language": "csharp" 17 | } 18 | -------------------------------------------------------------------------------- /samples/serial/scheduled-task-helper.ps1: -------------------------------------------------------------------------------- 1 | function Add-StartupScheduledTask 2 | { 3 | param ( 4 | [Parameter(Mandatory=$true)] 5 | [string] $TaskName, 6 | [Parameter(Mandatory=$true)] 7 | [string] $Execute, 8 | [string] $Argument 9 | ) 10 | 11 | $TaskDescription = $TaskName + ' enable serial over network connection' 12 | 13 | # the scheduled task will run in the background when system starts 14 | $Principal=New-ScheduledTaskPrincipal -UserId admin -LogonType S4U -Id Author 15 | $Trigger=New-ScheduledTaskTrigger -AtStartup 16 | $Action=New-ScheduledTaskAction -Execute $Execute -Argument $Argument 17 | 18 | #register and start the scheduled task 19 | Register-ScheduledTask -Action $Action -Trigger $Trigger -Principal $Principal -TaskName $TaskName -Description $TaskDescription 20 | Start-ScheduledTask -TaskName $TaskName 21 | } 22 | 23 | function Remove-StartupScheduledTask 24 | { 25 | param ( 26 | [Parameter(Mandatory=$true)] 27 | [string] $TaskName 28 | ) 29 | 30 | Stop-ScheduledTask -TaskName $TaskName 31 | Unregister-ScheduledTask -TaskName $TaskName 32 | } -------------------------------------------------------------------------------- /samples/serial/socat-daemon.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=service that uses socat to relay /dev/ttyVirtS0 to network connection 3 | After=network-online.target 4 | 5 | [Service] 6 | ExecStart=/usr/bin/socat pty,link=/dev/ttyVirtS0,raw,user=iotedge-user,group=dialout,mode=660 tcp:172.18.246.137:5002 7 | ExecReload=/bin/kill -s HUP $MAINPID 8 | ExecStop=/bin/kill -s QUIT $MAINPID 9 | 10 | [Install] 11 | WantedBy=multi-user.target --------------------------------------------------------------------------------