<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Chris McKelt</title>
    <description>The latest articles on DEV Community by Chris McKelt (@chris_mckelt).</description>
    <link>https://dev.to/chris_mckelt</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F159143%2F48720acf-56d4-418d-99c3-15a38aea13a4.jpg</url>
      <title>DEV Community: Chris McKelt</title>
      <link>https://dev.to/chris_mckelt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chris_mckelt"/>
    <language>en</language>
    <item>
      <title>dapr</title>
      <dc:creator>Chris McKelt</dc:creator>
      <pubDate>Thu, 10 Jul 2025 12:54:26 +0000</pubDate>
      <link>https://dev.to/chris_mckelt/dapr-456d</link>
      <guid>https://dev.to/chris_mckelt/dapr-456d</guid>
      <description></description>
      <category>dapr</category>
      <category>cloudnative</category>
      <category>microservices</category>
      <category>backenddevelopment</category>
    </item>
    <item>
      <title>Using Azure to setup a new blog and domain</title>
      <dc:creator>Chris McKelt</dc:creator>
      <pubDate>Sun, 03 Jan 2021 14:41:10 +0000</pubDate>
      <link>https://dev.to/chris_mckelt/using-azure-to-setup-a-new-blog-and-domain-4782</link>
      <guid>https://dev.to/chris_mckelt/using-azure-to-setup-a-new-blog-and-domain-4782</guid>
      <description>&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;Here is a quick way to setup a new WordPress blog with a custom domain on Azure (optionally using &lt;a href="https://azure.microsoft.com/en-au/free"&gt;free using credits&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Azure Resources Overview
&lt;/h3&gt;

&lt;p&gt;Resources used to setup the blog may be seen below. These were created within a single resource group called ‘blog’&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2021/01/1-resource-group-view.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zh-5XdGE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.mckelt.com/wp-content/uploads/2021/01/1-resource-group-view_thumb.png" title="1-resource-group-view" alt="1-resource-group-view" width="604" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  WordPress Setup
&lt;/h2&gt;

&lt;h5&gt;
  
  
  &lt;strong&gt;&lt;/strong&gt;
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;After logging into Azure go the the &lt;a href="https://portal.azure.com/?quickstart=true"&gt;marketplace&lt;/a&gt; and search for WordPress&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2021/01/2-wordpress-marketplace.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WSl_Rxfv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.mckelt.com/wp-content/uploads/2021/01/2-wordpress-marketplace_thumb.png" title="2-wordpress-marketplace" alt="2-wordpress-marketplace" width="604" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Click &lt;em&gt;create&lt;/em&gt; and begin to enter the details for your blog.  All resources below were created in a new resource group called ‘&lt;em&gt;blog’&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2021/01/3-create-from-marketplace.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rmewEHOa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.mckelt.com/wp-content/uploads/2021/01/3-create-from-marketplace_thumb.png" title="3-create-from-marketplace" alt="3-create-from-marketplace" width="604" height="724"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Create a new &lt;em&gt;App Service Plan&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2021/01/2-new-app-service-plan.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eSHREPd6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.mckelt.com/wp-content/uploads/2021/01/2-new-app-service-plan_thumb.png" title="2-new-app-service-plan" alt="2-new-app-service-plan" width="604" height="162"&gt;&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here we are using the cheapest pricing tier that allows a custom domain: ‘B1 Basic’ Tier&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2021/01/spec-picker.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2pBarjDX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.mckelt.com/wp-content/uploads/2021/01/spec-picker_thumb.png" title="spec-picker" alt="spec-picker" width="604" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configure a new database server using the ‘Basic’ pricing tier&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2021/01/database-server.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rd0q3_yr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.mckelt.com/wp-content/uploads/2021/01/database-server_thumb.png" title="database-server" alt="database-server" width="604" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2021/01/pricing-tier.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Jya2HFvQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.mckelt.com/wp-content/uploads/2021/01/pricing-tier_thumb.png" title="pricing-tier" alt="pricing-tier" width="604" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;After clicking the create button a new WordPress App Service will be deployed and available to configure on_ YourBlogSite.azurewebsites.net_&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Navigate to the website and configure your WordPress instance.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2021/01/english.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RiNgymoL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.mckelt.com/wp-content/uploads/2021/01/english_thumb.png" title="english" alt="english" width="604" height="877"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Next we will setup a custom website domain to use for the blog using &lt;a href="https://docs.microsoft.com/en-us/azure/app-service/manage-custom-dns-buy-domain"&gt;App Service Domains&lt;/a&gt;.
App Service domains are custom domains that are managed directly in Azure. They make it easy to manage custom domains for &lt;a href="https://docs.microsoft.com/en-us/azure/app-service/overview"&gt;Azure App Service&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://portal.azure.com/?quickstart=true#create/Microsoft.Domain"&gt;Create your App Service Domain&lt;/a&gt; and choose a TLD domain name for your website.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2021/01/create-app-services-domain-1.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1UtWy3-T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.mckelt.com/wp-content/uploads/2021/01/create-app-services-domain-1_thumb.png" title="create-app-services-domain-1" alt="create-app-services-domain-1" width="604" height="589"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enter your contact information required by GoDaddy for domain registration and Azure DNS to host the domains. In addition to the yearly domain registration fee, usage charges for Azure DNS apply. For information, see Azure DNS Pricing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2021/01/create-app-services-domain-2.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wEJmBAYa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.mckelt.com/wp-content/uploads/2021/01/create-app-services-domain-2_thumb.png" title="create-app-services-domain-2" alt="create-app-services-domain-2" width="604" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create you App Service Domain, it may take a while for the DNS to propagate and be ready for use&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2021/01/app-service-domain-deployment-2.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C4CV0gcj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.mckelt.com/wp-content/uploads/2021/01/app-service-domain-deployment-2_thumb.png" title="app-service-domain-deployment-2" alt="app-service-domain-deployment-2" width="604" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your App Service Domain and add a hostname binding pointing to the App Service that hosts your WordPress blog.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2021/01/hostname-bindings.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VnOMoVrm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.mckelt.com/wp-content/uploads/2021/01/hostname-bindings_thumb.png" title="hostname-bindings" alt="hostname-bindings" width="604" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You should now be able to browse to your custom domain and see your WordPress site. Thats it!&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;So we now have a WordPress website setup with a custom domain without leaving the Azure portal.&lt;/p&gt;

&lt;p&gt;Next steps will be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a free SSL certificate via Lets Encrypt to host the site under SSL&lt;/li&gt;
&lt;li&gt;Follow Azure guidelines to &lt;a href="https://techcommunity.microsoft.com/t5/azure-database-for-mysql/improving-your-wordpress-workloa-performance-on-azure-database/ba-p/1418717"&gt;improve&lt;/a&gt; WordPress performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please let us know how you go with setting up your own site.&lt;/p&gt;

&lt;p&gt;Happy blogging!&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>azure</category>
      <category>wordpress</category>
      <category>blog</category>
    </item>
    <item>
      <title>Azure IoT Edge – using Grafana on the Edge</title>
      <dc:creator>Chris McKelt</dc:creator>
      <pubDate>Sat, 02 May 2020 03:37:06 +0000</pubDate>
      <link>https://dev.to/chris_mckelt/azure-iot-edge-using-grafana-on-the-edge-26na</link>
      <guid>https://dev.to/chris_mckelt/azure-iot-edge-using-grafana-on-the-edge-26na</guid>
      <description>&lt;h1&gt;
  
  
  Series
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-who-is-cooler-dotnet-node-or-python-369m"&gt; &lt;br&gt;
Part 1 - dotnet vs python vs node - temperature emission - who is cooler?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-developing-custom-modules-df3"&gt;Part 2 - Developing modules&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-3rd-party-containers-3mi3"&gt;Part 3 - Custom Containers using Apache Nifi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-using-timescaledb-on-the-edge-2ec1"&gt;Part 4 - Custom Module using TimescaleDB&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-using-grafana-on-the-edge-26na"&gt;Part 5 - Custom Module using Grafana&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;Intro&lt;/h1&gt;

&lt;p&gt;This is part 5 in a series starting &lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-who-is-cooler-dotnet-node-or-python-369m"&gt;here&lt;/a&gt; that runs through building an &lt;a href="https://docs.microsoft.com/en-us/azure/iot-edge/about-iot-edge"&gt;Azure IOT Edge&lt;/a&gt; solution. This post will run through setting up &lt;a href="https://grafana.com/"&gt;Grafana&lt;/a&gt; to visualise temperature readings sent from the dot net, python and node custom edge modules.&lt;/p&gt;

&lt;p&gt;The code is located at: &lt;a href="https://github.com/chrismckelt/edgy"&gt;https://github.com/chrismckelt/edgy&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://grafana.com/"&gt;Grafana&lt;/a&gt; is the open source analytics and monitoring solution for every database&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Steps to add the module&lt;/h2&gt;

&lt;h3&gt;1. add a new &lt;a href="https://github.com/chrismckelt/edgy/tree/master/modules/Grafana"&gt;custom module&lt;/a&gt; &lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jh6v7-Iw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80546306-e1627c00-89e7-11ea-8ceb-434b79aed040.png" class="article-body-image-wrapper"&gt;&lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--jh6v7-Iw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80546306-e1627c00-89e7-11ea-8ceb-434b79aed040.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;2. add a new &lt;a href="https://github.com/chrismckelt/edgy/blob/master/deployment.debug.grafana.template.json"&gt;deployment file&lt;/a&gt; just for Grafana (and amend the &lt;a href="https://github.com/chrismckelt/edgy/blob/master/deployment.debug.template.json"&gt;full solution file&lt;/a&gt;)&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GMH9WXgs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80546722-03a8c980-89e9-11ea-8735-051f381f16a3.png" class="article-body-image-wrapper"&gt;&lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--GMH9WXgs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80546722-03a8c980-89e9-11ea-8735-051f381f16a3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;3. create the &lt;a href="https://github.com/chrismckelt/edgy/blob/master/modules/Grafana/Dockerfile.amd64.debug"&gt;docker file&lt;/a&gt;
&lt;/h3&gt;

&lt;h6&gt;FROM grafana/grafana:latest&lt;/h6&gt;

&lt;h6&gt;# login with admin and below password to web interface&lt;/h6&gt;

&lt;h6&gt;ENV GF_SECURITY_ADMIN_PASSWORD [&lt;em&gt;YOUR_GRAFANA_PASSWORD_HERE]&lt;/em&gt;
&lt;/h6&gt;

&lt;h6&gt;ENV GF_AUTH_LDAP_ENABLED=false&lt;/h6&gt;

&lt;h6&gt;ENV GF_DATABASE_TYPE postgres&lt;/h6&gt;

&lt;h6&gt;ENV GF_DATABASE_HOST timescaledb&lt;/h6&gt;

&lt;h6&gt;ENV GF_DATABASE_NAME grafana&lt;/h6&gt;

&lt;h6&gt;ENV GF_DATABASE_USER grafana&lt;/h6&gt;

&lt;h6&gt;ENV GF_DATABASE_PASSWORD [&lt;em&gt;YOUR_DATABASE_PASSWORD_HERE]&lt;/em&gt;
&lt;/h6&gt;

&lt;h6&gt;COPY ldap.toml /etc/grafana/&lt;/h6&gt;

&lt;h6&gt;COPY custom.ini /etc/grafana/&lt;/h6&gt;

&lt;h3&gt;4. create the &lt;a href="https://github.com/chrismckelt/edgy/blob/master/modules/Grafana/custom.ini"&gt;custom.ini&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;make sure to enter the database password on line 75&lt;/p&gt;

&lt;h3&gt;5. build and run IoT Edge solution in simulator&lt;/h3&gt;

&lt;h6&gt;&lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--DH7Bu8Ad--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80850862-d5c5be00-8c50-11ea-8cda-67a65caf058f.png"&gt;&lt;/h6&gt;

&lt;h3&gt;6. Navigate to &lt;a href="http://localhost:8082/"&gt;http://localhost:8082/&lt;/a&gt; and login (admin + your grafana password)&lt;/h3&gt;

&lt;p&gt;The Grafana setup board should appear as below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZpA8FL-a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80850936-36ed9180-8c51-11ea-9152-9714976a00f7.png" class="article-body-image-wrapper"&gt;&lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZpA8FL-a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80850936-36ed9180-8c51-11ea-9152-9714976a00f7.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;7. Add data source –&amp;gt; PostgreSQL&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g0TbNZ9F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80851051-de6ac400-8c51-11ea-9b9c-9498307fcbef.png" class="article-body-image-wrapper"&gt;&lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--g0TbNZ9F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80851051-de6ac400-8c51-11ea-9b9c-9498307fcbef.png"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h3&gt;8. Add a dashboard query &amp;amp; set the query as below&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2sRrebpn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80911764-144f9b80-8d6b-11ea-96cb-1f1c24432b4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2sRrebpn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80911764-144f9b80-8d6b-11ea-96cb-1f1c24432b4f.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A time series graph will display the 3 temperature readings over time.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2DAE3tSC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80911783-2598a800-8d6b-11ea-9a48-b21db723b8f0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2DAE3tSC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/80911783-2598a800-8d6b-11ea-9a48-b21db723b8f0.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;Outro&lt;/h1&gt;

&lt;p&gt;Here we have added Grafana to our IoT Edge solution and created a dashboard from the data stored in &lt;a href="https://www.timescale.com/"&gt;TimescaleDB&lt;/a&gt;. The generated temperature sent from the 3 modules is analysed by &lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-3rd-party-containers-3mi3"&gt;Apache Nifi&lt;/a&gt;. When the temperature is greater than 25 degrees a request is sent back to the specific module to activate the air conditioner, which makes the temperature randomly decrease over time.&lt;/p&gt;

&lt;p&gt;Think I would prefer the Python room as it appears the &lt;a href="https://user-images.githubusercontent.com/662868/80854122-2bf22b80-8c68-11ea-919c-4833ac0847b8.png"&gt;coolest!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>azure</category>
      <category>docker</category>
      <category>grafana</category>
      <category>azureiot</category>
    </item>
    <item>
      <title>Azure IoT Edge – using TimescaleDB on the Edge</title>
      <dc:creator>Chris McKelt</dc:creator>
      <pubDate>Sun, 12 Apr 2020 06:41:47 +0000</pubDate>
      <link>https://dev.to/chris_mckelt/azure-iot-edge-using-timescaledb-on-the-edge-2ec1</link>
      <guid>https://dev.to/chris_mckelt/azure-iot-edge-using-timescaledb-on-the-edge-2ec1</guid>
      <description>&lt;h1&gt;
  
  
  Series
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-who-is-cooler-dotnet-node-or-python-369m"&gt; &lt;br&gt;
Part 1 - dotnet vs python vs node - temperature emission - who is cooler?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-developing-custom-modules-df3"&gt;Part 2 - Developing modules&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-3rd-party-containers-3mi3"&gt;Part 3 - Custom Containers using Apache Nifi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-using-timescaledb-on-the-edge-2ec1"&gt;Part 4 - Custom Module using TimescaleDB&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-using-grafana-on-the-edge-26na"&gt;Part 5 - Custom Module using Grafana&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;This is part 4 in a series starting &lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-who-is-cooler-dotnet-node-or-python-369m"&gt;here&lt;/a&gt; that runs through building an &lt;a href="https://docs.microsoft.com/en-us/azure/iot-edge/about-iot-edge" rel="noopener noreferrer"&gt;Azure IOT Edge&lt;/a&gt; solution. This post will run through setting up &lt;a href="https://www.timescale.com/" rel="noopener noreferrer"&gt;TimescaleDB&lt;/a&gt; to store data published from the dotnet, python and node temperature modules.&lt;/p&gt;

&lt;p&gt;The code is located at: &lt;a href="https://github.com/chrismckelt/edgy" rel="noopener noreferrer"&gt;https://github.com/chrismckelt/edgy&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.timescale.com/" rel="noopener noreferrer"&gt;TimescaleDB&lt;/a&gt;: An open-source database built for analysing&lt;/p&gt;

&lt;p&gt;time-series data with the power and convenience of&lt;/p&gt;

&lt;p&gt;SQL — on premise, at the edge or in the cloud.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Steps to add the database
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. add the &lt;a href="https://github.com/chrismckelt/edgy/tree/master/modules/TimescaleDb" rel="noopener noreferrer"&gt;custom module&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F662868%2F79062247-060de280-7ccb-11ea-901d-7faa07663fd6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F662868%2F79062247-060de280-7ccb-11ea-901d-7faa07663fd6.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  2. add the section to the &lt;a href="https://github.com/chrismckelt/edgy/blob/master/deployment.debug.template.json" rel="noopener noreferrer"&gt;deployment file&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Expose the internal port 5432 that TimescaleDB uses to 8081 for external container use&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  3. create the &lt;a href="https://github.com/chrismckelt/edgy/blob/master/modules/TimescaleDb/Dockerfile.amd64.debug" rel="noopener noreferrer"&gt;docker file&lt;/a&gt;
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  4. create the &lt;a href="https://github.com/chrismckelt/edgy/blob/master/modules/TimescaleDb/init.sql" rel="noopener noreferrer"&gt;database, login and schema&lt;/a&gt;
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  5. run the container and insert data from another module
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h6&gt;
  
  
      select * from “table_001” where Isairconditioneron = 0 ORDER BY “Timestamp” DESC LIMIT 100;
&lt;/h6&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F662868%2F79062131-078adb00-7cca-11ea-975e-6885c0ba70ce.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F662868%2F79062131-078adb00-7cca-11ea-975e-6885c0ba70ce.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Outro
&lt;/h1&gt;

&lt;p&gt;Now we have data being saved into the database we can move onto displaying it visually via &lt;a href="https://grafana.com/" rel="noopener noreferrer"&gt;Grafana&lt;/a&gt; in the next post.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>azureiotedge</category>
      <category>timescale</category>
    </item>
    <item>
      <title>Azure IoT Edge – Using Apache Nifi as a 3rd party container</title>
      <dc:creator>Chris McKelt</dc:creator>
      <pubDate>Thu, 02 Apr 2020 16:33:30 +0000</pubDate>
      <link>https://dev.to/chris_mckelt/azure-iot-edge-3rd-party-containers-3mi3</link>
      <guid>https://dev.to/chris_mckelt/azure-iot-edge-3rd-party-containers-3mi3</guid>
      <description>&lt;h1&gt;
  
  
  Series
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-who-is-cooler-dotnet-node-or-python-369m"&gt; &lt;br&gt;
Part 1 - dotnet vs python vs node - temperature emission - who is cooler?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-developing-custom-modules-df3"&gt;Part 2 - Developing modules&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-3rd-party-containers-3mi3"&gt;Part 3 - Custom Containers using Apache Nifi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-using-timescaledb-on-the-edge-2ec1"&gt;Part 4 - Custom Module using TimescaleDB&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-using-grafana-on-the-edge-26na"&gt;Part 5 - Custom Module using Grafana&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;=====&lt;/p&gt;

&lt;p&gt;This is part 3 in a series starting &lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-who-is-cooler-dotnet-node-or-python-369m"&gt;here&lt;/a&gt; that runs through building an &lt;a href="https://docs.microsoft.com/en-us/azure/iot-edge/about-iot-edge"&gt;Azure IOT Edge&lt;/a&gt; solution. This post will run through setting up a 3rd party docker container for an edge deployment.  &lt;br&gt;&lt;br&gt;
The code is located at: &lt;a href="https://github.com/chrismckelt/edgy"&gt;https://github.com/chrismckelt/edgy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to manage data flow &amp;amp; logic on the edge we will deploy a data orchestrator.  There are quite a few &lt;a href="https://stackshare.io/apache-nifi/alternatives"&gt;choices&lt;/a&gt; on the market – for this demo we will use Apache Nifi &lt;a href="https://nifi.apache.org/"&gt;https://nifi.apache.org/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nifi.apache.org/"&gt;Apache Nifi&lt;/a&gt; describes itself as ‘&lt;em&gt;An easy to use, powerful, and reliable system to process and distribute data&lt;/em&gt;.’&lt;/p&gt;

&lt;h2&gt;
  
  
  What will this module do?
&lt;/h2&gt;

&lt;p&gt;The Nifi module will listen to the dot net, python &amp;amp; node module messages and when a temperature exceeds 25°C it will publish a message to activate the air conditioning.  The over heating module will receive the message and turn the air conditioning on, thus decrease the temperature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m-n00mc_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78258726-3963ab00-752e-11ea-91fa-90ff4d0e13a7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m-n00mc_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78258726-3963ab00-752e-11ea-91fa-90ff4d0e13a7.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This work was inspired by the following project:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/iotblackbelt/nifimodule"&gt;https://github.com/iotblackbelt/nifimodule&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up Nifi
&lt;/h1&gt;

&lt;p&gt;To connect Nifi to the edge hub MQTT/AMQP broker (and not using the inbuilt &lt;a href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-sdks"&gt;SDKs&lt;/a&gt; with code), we need to authenticate with self signed certificates.&lt;/p&gt;

&lt;p&gt;The easiest way to use self signed certificates for Azure IoT Edge is to follow this tutorial &lt;a href="https://docs.microsoft.com/en-us/azure/iot-edge/tutorial-machine-learning-edge-05-configure-edge-device"&gt;https://docs.microsoft.com/en-us/azure/iot-edge/tutorial-machine-learning-edge-05-configure-edge-device&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I use the docker image provided in that tutorial to generate my self signed certs. After following the tutorial I upload the ROOT CA to the Azure IoT Hub. After verification it should appear as below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8duHmcbH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78261684-1a671800-7532-11ea-932b-eda711d33355.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8duHmcbH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78261684-1a671800-7532-11ea-932b-eda711d33355.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When working &lt;strong&gt;locally&lt;/strong&gt; with the simulator you will use the generated certs from VS Code. These are found at &lt;em&gt;C:\ProgramData\iotedgehubdev&lt;/em&gt;        &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i60s7EvV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78262241-dfb1af80-7532-11ea-82a1-d25141004479.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i60s7EvV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78262241-dfb1af80-7532-11ea-82a1-d25141004479.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment files
&lt;/h2&gt;

&lt;p&gt;For debugging purposes I made a deployment file that runs only the &lt;em&gt;DotNetGenerator&lt;/em&gt; &amp;amp; &lt;em&gt;Nifi&lt;/em&gt;.   The sections below are also in the full local debug and production template. &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qsmDNdBq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78413894-1c24fe80-764c-11ea-8bd6-0d4fbea22bad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qsmDNdBq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78413894-1c24fe80-764c-11ea-8bd6-0d4fbea22bad.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Nifi config setup
&lt;/h2&gt;

&lt;p&gt;When the Nifi docker file starts it will execute a &lt;a href="https://github.com/chrismckelt/edgy/blob/master/modules/Nifi/local.sh"&gt;script&lt;/a&gt; to do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; copy existing files from the local computer using docker bind from c:/config  to /config &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--czZbprrX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78266974-0bd02f00-7539-11ea-8afb-e49490273913.png" alt=""&gt;
&lt;/li&gt;
&lt;li&gt; copy the self signed certificates to the Java cert store&lt;/li&gt;
&lt;li&gt; restart Nifi so the certs and new configuration apply&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Nifi authentication
&lt;/h2&gt;

&lt;p&gt;To connect and publish messages to the MQTT broker we add the following processors in our Nifi flow&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  ConsumeMQTT&lt;/li&gt;
&lt;li&gt;  PublishMQTT&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8B39VofP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78415336-b3da1b00-7653-11ea-8704-90bfe2007a5a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8B39VofP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78415336-b3da1b00-7653-11ea-8704-90bfe2007a5a.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon adding a processor you will need to enter the connection details and configure a &lt;em&gt;SSL Context Service&lt;/em&gt;  to connect to the edge hub broker.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nw1I_S7q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78415309-7bd2d800-7653-11ea-8683-ff076cd14baf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nw1I_S7q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78415309-7bd2d800-7653-11ea-8683-ff076cd14baf.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  SSL Context Service setting (certs used are stored in the Java cert store)
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--088Jx9uQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78415387-fac81080-7653-11ea-8d80-4f8fbdb1307b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--088Jx9uQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78415387-fac81080-7653-11ea-8d80-4f8fbdb1307b.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Settings
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DP2tsLYO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78469090-5bd50e80-7750-11ea-8222-b22a6d8947c8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DP2tsLYO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78469090-5bd50e80-7750-11ea-8222-b22a6d8947c8.png" alt=""&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h6&gt;
  
  
  To generate a SAS token, right click on the device and select ‘Generate SAS Token for Device’
&lt;/h6&gt;

&lt;h4&gt;
  
  
   &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c2B09_sA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78415646-9c039680-7655-11ea-8d6c-5781fbdb4171.png" alt=""&gt;
&lt;/h4&gt;

&lt;h2&gt;
  
  
  Nifi logic to air con control
&lt;/h2&gt;

&lt;p&gt;Using the inbuilt IoT routing system temperature payloads published from dot net, python &amp;amp; node will be pushed to Nifi.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AME5Gc1u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78415724-4aa7d700-7656-11ea-9047-1d3f03e01ca8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AME5Gc1u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78415724-4aa7d700-7656-11ea-9047-1d3f03e01ca8.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nifi checks if the temperature recording exceeds 25°C.  When this occurs it will publish its own message which is routed back to the overheating module requesting it to turn on the air con.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MfFqHGQJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78273205-1989b280-7541-11ea-92c4-eb9f92153fa2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MfFqHGQJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78273205-1989b280-7541-11ea-92c4-eb9f92153fa2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Nifi this translates to the following processor flows (probably a better way to do this – Nifi experts?)&lt;/p&gt;

&lt;h2&gt;
  
  
  Nifi flows
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eGBp_KdD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78217920-85432f80-74ef-11ea-80db-e92bd4f2b850.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eGBp_KdD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78217920-85432f80-74ef-11ea-80db-e92bd4f2b850.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the solution locally
&lt;/h2&gt;

&lt;p&gt;Upon starting the solution each module will publish a temperature starting at 20°C .   Nifi will receive each message via the Consume MQTT processor.  Viewing the data provenance shows all received messages:&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z5jFn1JZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78442149-d8151680-76aa-11ea-9f33-504390a7487b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z5jFn1JZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78442149-d8151680-76aa-11ea-9f33-504390a7487b.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The modules keep publishing increasing temperatures until Nifi received a temperature over 25°C.  Nifi then publishes a message requesting the respective module (e.g. &lt;em&gt;PythonDataGenerator&lt;/em&gt;) to decrease the temperature (turn on the air con).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fGq9xMoT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78723470-0e2df100-795e-11ea-8ebf-75294a7beb1c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fGq9xMoT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78723470-0e2df100-795e-11ea-8ebf-75294a7beb1c.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch out when publishing your container to ACR
&lt;/h2&gt;

&lt;p&gt;Be careful when publishing your local containers to your remote container registry.  I was publishing direct from my machine to my Azure Container Registry. Meanwhile the environment variables were set to look for certificates in the wrong place. So Nifi would not authenticate.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x9SFUtka--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/78264086-5354bc00-7535-11ea-854d-f468f1f45e44.png" alt=""&gt;
&lt;/h2&gt;

&lt;h1&gt;
  
  
  Outro
&lt;/h1&gt;

&lt;p&gt;Here we have shown how to build and deploy a 3rd party container in our edge solution.  Once we have the installed the custom certificates Nifi can authenticate to the edge hub and send/receive messages.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>azureiotedge</category>
      <category>nifi</category>
      <category>docker</category>
    </item>
    <item>
      <title>AZURE IOT EDGE – Developing custom modules</title>
      <dc:creator>Chris McKelt</dc:creator>
      <pubDate>Tue, 10 Mar 2020 02:00:04 +0000</pubDate>
      <link>https://dev.to/chris_mckelt/azure-iot-edge-developing-custom-modules-df3</link>
      <guid>https://dev.to/chris_mckelt/azure-iot-edge-developing-custom-modules-df3</guid>
      <description>&lt;h1&gt;
  
  
  Series
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-who-is-cooler-dotnet-node-or-python-369m"&gt; &lt;br&gt;
Part 1 - dotnet vs python vs node - temperature emission - who is cooler?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-developing-custom-modules-df3"&gt;Part 2 - Developing modules&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-3rd-party-containers-3mi3"&gt;Part 3 - Custom Containers using Apache Nifi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-using-timescaledb-on-the-edge-2ec1"&gt;Part 4 - Custom Module using TimescaleDB&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-using-grafana-on-the-edge-26na"&gt;Part 5 - Custom Module using Grafana&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;This is part 2 in a series starting &lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-who-is-cooler-dotnet-node-or-python-369m"&gt;here&lt;/a&gt; that runs through an Azure IOT Edge solution located at: &lt;a href="https://github.com/chrismckelt/edgy"&gt;https://github.com/chrismckelt/edgy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This part will cover developing and running custom modules written in C#, Python and NodeJS.&lt;/p&gt;

&lt;p&gt;It will focus on commands available in the VS Code interface rather than command line arguments as seen at: &lt;a href="https://aka.ms/iotedgedev"&gt;https://aka.ms/iotedgedev&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Azure IoT SDKs
&lt;/h2&gt;

&lt;p&gt;Azure IoT Edge has a number of &lt;a href="https://github.com/Azure/azure-iot-sdks"&gt;SDKs&lt;/a&gt; for module development in your favourite language.  The &lt;a href="https://github.com/Azure/azure-iot-sdks"&gt;SDK code&lt;/a&gt; will handle setting up environment variables and provide the boiler plate code necessary to send and receive messages using multiple &lt;a href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-protocols"&gt;protocols &amp;amp; channels  (e.g. MQTT, AMQP)&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-protocols"&gt;Setting up VS Code to run the local simulator&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Given the solution is cloned locally and Azure is setup with our IOT Hub we can configure a device to act as a local simulator.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select IOT Hub &amp;amp; choose your IOT Hub&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V-NGov-i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226837-4390bb80-6bb6-11ea-8a88-e03f10cc02eb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V-NGov-i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226837-4390bb80-6bb6-11ea-8a88-e03f10cc02eb.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create IOT Edge Device - I have named my local device ‘&lt;em&gt;LocalSimulator&lt;/em&gt; ‘ &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UTVteo8f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226840-4ab7c980-6bb6-11ea-8380-b0656965b968.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UTVteo8f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226840-4ab7c980-6bb6-11ea-8380-b0656965b968.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setup IOT Edge Simulator – this will create you edge certs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kCTXFXDi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226898-bd28a980-6bb6-11ea-99cb-3f5a35dce53a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kCTXFXDi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226898-bd28a980-6bb6-11ea-99cb-3f5a35dce53a.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will generate and install certificates for local development in the following folder &amp;amp; also install the for you &lt;em&gt;note://run VS Code as admin for this&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZIqFZrqX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226845-5905e580-6bb6-11ea-881e-46ca8640529b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZIqFZrqX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226845-5905e580-6bb6-11ea-881e-46ca8640529b.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating a module for our solution
&lt;/h2&gt;

&lt;p&gt;Right click on the modules folder and select ‘Add IoT Edge Module’. &lt;/p&gt;

&lt;p&gt;This will then ask a module name &amp;amp; language (C,C#,Java,Node.js, Python)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VWtJkQ7z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226850-615e2080-6bb6-11ea-9775-f2a18775b707.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VWtJkQ7z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226850-615e2080-6bb6-11ea-9775-f2a18775b707.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post will focus on the data generator/recorder modules below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uJe7WQ9x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226855-67ec9800-6bb6-11ea-9af9-3bf33e1fbc44.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uJe7WQ9x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226855-67ec9800-6bb6-11ea-9af9-3bf33e1fbc44.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Data Generators
&lt;/h2&gt;

&lt;p&gt;The demo code shows 3 ‘data generator’ modules written in C#, Python &amp;amp; Node JS.&lt;/p&gt;

&lt;p&gt;Each module publishes a message every second simulating temperature capture.  Properties of the sent message are:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In C# connecting to the Edge Hub and sending messages can be seen in the following code:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Data Recorders
&lt;/h2&gt;

&lt;p&gt;3 modules in matching languages subscribe to their respective modules published messages&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Messages received are deserialized from JSON format to a POCO and then saved in a database.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Routes
&lt;/h2&gt;

&lt;p&gt;In order to route messages between modules we use the inbuilt route system in our &lt;a href="https://github.com/chrismckelt/edgy/blob/master/deployment.debug.template.json"&gt;deployment template&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--70A47-Dr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226859-75a21d80-6bb6-11ea-9723-f7f977688da2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--70A47-Dr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226859-75a21d80-6bb6-11ea-9723-f7f977688da2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Web App – Viewer module
&lt;/h2&gt;

&lt;p&gt;Finally to view the messages from a web page I have modified an &lt;a href="https://github.com/Azure-Samples/iot-edge-hmi-module"&gt;existing demo to&lt;/a&gt; that uses SignalR view all messages sent to it from the below routes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WyYx_IiC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226864-7a66d180-6bb6-11ea-8e78-30165268a5d3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WyYx_IiC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226864-7a66d180-6bb6-11ea-8e78-30165268a5d3.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When running the solution you can view all published messages on the web page below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2ZSrb5gu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226868-7f2b8580-6bb6-11ea-991e-f88f499d70b7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2ZSrb5gu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77226868-7f2b8580-6bb6-11ea-991e-f88f499d70b7.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Outro
&lt;/h2&gt;

&lt;p&gt;Here was a basic overview of an demo solution to create and build your own custom IoT Edge modules.&lt;/p&gt;

&lt;p&gt;Next we will introduce an existing docker container (&lt;a href="https://nifi.apache.org/"&gt;Apache Nifi&lt;/a&gt;) to act as a data orchestrator.  This will subscribe to all 'Payload' messages and publish a message to ‘turn off’ the air conditioner when the temperature is too high.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>iot</category>
      <category>iotedge</category>
    </item>
    <item>
      <title>Azure IoT Edge - dotnet, node python</title>
      <dc:creator>Chris McKelt</dc:creator>
      <pubDate>Thu, 13 Feb 2020 13:00:51 +0000</pubDate>
      <link>https://dev.to/chris_mckelt/azure-iot-edge-who-is-cooler-dotnet-node-or-python-369m</link>
      <guid>https://dev.to/chris_mckelt/azure-iot-edge-who-is-cooler-dotnet-node-or-python-369m</guid>
      <description>&lt;h1&gt;
  
  
  Series
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-who-is-cooler-dotnet-node-or-python-369m"&gt; &lt;br&gt;
Part 1 - dotnet vs python vs node - temperature emission - who is cooler?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-developing-custom-modules-df3"&gt;Part 2 - Developing modules&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-3rd-party-containers-3mi3"&gt;Part 3 - Custom Containers using Apache Nifi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-using-timescaledb-on-the-edge-2ec1"&gt;Part 4 - Custom Module using TimescaleDB&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/chris_mckelt/azure-iot-edge-using-grafana-on-the-edge-26na"&gt;Part 5 - Custom Module using Grafana&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;This code will run through creating an end to end demo of building &amp;amp; deploying an &lt;a href="https://docs.microsoft.com/en-us/azure/iot-edge/about-iot-edge"&gt;Azure IoT Edge&lt;/a&gt; solution.&lt;/p&gt;

&lt;h4&gt;
  
  
  Code for this example lives here
&lt;/h4&gt;

&lt;h5&gt;
  
  
  &lt;a href="https://github.com/chrismckelt/edgy"&gt;https://github.com/chrismckelt/edgy&lt;/a&gt;
&lt;/h5&gt;

&lt;h2&gt;
  
  
  Whats the demo?
&lt;/h2&gt;

&lt;p&gt;This solution demonstrates an air-conditioning monitoring system where 3 room sensors are publishing their temperature over time.   When a room gets too hot the air conditioner for that room is turned on. Once the room is cooled it is turned off.&lt;/p&gt;

&lt;p&gt;Three ‘data generator’ modules publish a message with the following properties.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;span&gt;&lt;em&gt;Timestamp&lt;/em&gt; &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;span&gt;&lt;em&gt;Temperature&lt;/em&gt; –   room temp in Celsius&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;span&gt;&lt;em&gt;IsAirConditionerOn&lt;/em&gt; – true/false&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;span&gt;&lt;em&gt;TagKey&lt;/em&gt; – room name (in this case  dotnet, node, python)&lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three ‘data recorder’ modules subscribe to the published temperature messages and save the data in a time series database.&lt;/p&gt;

&lt;p&gt;A custom module will listen to all temperature messages and analyse when a room is too hot. Sending a message to turn the rooms air conditioner on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1namitZd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76138797-6afb6a80-6085-11ea-93dd-2a8fda17583a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1namitZd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76138797-6afb6a80-6085-11ea-93dd-2a8fda17583a.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo Focus Areas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; show local debug/development options &amp;amp;  remote/real deployment&lt;/li&gt;
&lt;li&gt; how to create and configure an Azure IOT Hub environment in Azure &lt;a href="https://github.com/chrismckelt/edgy/tree/master/scripts/environment"&gt;using Azure CLI scripts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; coding custom modules in .Net, Python, NodeJS (sorry Java)&lt;/li&gt;
&lt;li&gt; using existing &lt;a href="https://aka.ms/iot-edge-marketplace"&gt;Azure IoT Edge marketplace&lt;/a&gt; modules&lt;/li&gt;
&lt;li&gt; using non-edge marketplace modules (docker images) to save data with &lt;a href="https://www.timescale.com/"&gt;Timescale&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; connecting a data flow engine ( &lt;a href="https://nifi.apache.org/"&gt;Apache Nifi&lt;/a&gt;) to the Edge &lt;a href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-mqtt-support"&gt;MQTT Broker&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; viewing the data through a &lt;a href="https://grafana.com/"&gt;Grafana&lt;/a&gt; dashboard.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Getting started
&lt;/h1&gt;

&lt;p&gt;In order to develop solutions for the edge:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Read &lt;a href="https://docs.microsoft.com/en-us/azure/iot-edge/how-to-vs-code-develop-module"&gt;Developing custom modules&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Setup your machine using the &lt;a href="https://github.com/Azure/iotedgedev"&gt;Azure IoT EdgeHub Dev Tool&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; I recommend installing these &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.azure-iot-edge"&gt;VS code extensions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; I recommend using &lt;a href="https://www.portainer.io/"&gt;Portainer&lt;/a&gt; for docker management both locally &amp;amp; on the deployed edge solution&lt;/li&gt;
&lt;/ol&gt;

&lt;h6&gt;
  
  
  Portainer running on &lt;a href="http://localhost:9000/"&gt;http://localhost:9000/&lt;/a&gt;
&lt;/h6&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0hUgzmlZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76701501-ae487f80-66fc-11ea-861a-2f04c19bdf56.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0hUgzmlZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76701501-ae487f80-66fc-11ea-861a-2f04c19bdf56.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Solution Overview
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Azure Setup
&lt;/h2&gt;

&lt;p&gt;You will need an &lt;a href="https://azure.microsoft.com/en-us/pricing/details/iot-hub/"&gt;Azure IoT Hub&lt;/a&gt; setup in Azure.   For this demo I am using the free tier&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The IoT Hub Free Edition is intended to encourage proof of concept projects. It enables you to transmit up to a total of 8,000 messages per day, and register up to 500 device identities. The device identity limit is only present for the Free Edition.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To build the environment I have used the Azure CLI and created scripts found &lt;a href="https://github.com/chrismckelt/edgy/tree/master/scripts/environment"&gt;here&lt;/a&gt;.   Run the top 3 on your selected subscription to create the artefacts in Azure below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WyPDaodM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77835944-caccc900-718c-11ea-815a-b75fc729905b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WyPDaodM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/77835944-caccc900-718c-11ea-815a-b75fc729905b.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Cg-ed4Wu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/75735359-75d89700-5d35-11ea-8b46-9e5be2274d46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Cg-ed4Wu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/75735359-75d89700-5d35-11ea-8b46-9e5be2274d46.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Modules
&lt;/h2&gt;

&lt;p&gt;The code contains the docker build files , code &amp;amp; scripts to create the following modules&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6oxf48-L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/75736364-fa2c1980-5d37-11ea-99f9-42eb41fb7ea1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6oxf48-L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/75736364-fa2c1980-5d37-11ea-99f9-42eb41fb7ea1.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Descriptions of folders and files
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;th&gt;Folder /  File&lt;/th&gt;

&lt;th&gt;Description&lt;/th&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;config&lt;/td&gt;

&lt;td&gt;automatically generate files from the deployment.templates.json (debug or prod) that are used to deploy the solution&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;modules&lt;/td&gt;

&lt;td&gt;custom code, docker images for your IOT Edge solution&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;scripts&lt;/td&gt;

&lt;td&gt;code to create the environment, build the code/docker images and deploy the solution&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;tools&lt;/td&gt;

&lt;td&gt;certificate generator and other tools for solution support&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;.env&lt;/td&gt;

&lt;td&gt;holds environment variables that populate the generated config files from the templates&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;deployment.debug.template.json&lt;/td&gt;

&lt;td&gt;  creates a file in the /config folder called 'deployment.debug.json' that populates environment variables, used for local development&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;deployment.prod.template.json&lt;/td&gt;

&lt;td&gt;creates a file in the /config folder called 'deployment.prod.json' that populates environment variables, used for production like deployment&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Solution Structure Overview
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_KTTr43x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/75339444-81f2cd80-58cb-11ea-8c08-eb485e8b5e4b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_KTTr43x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/75339444-81f2cd80-58cb-11ea-8c08-eb485e8b5e4b.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Azure IOT Edge Devices
&lt;/h2&gt;

&lt;p&gt;The solution used 3 devices which will be setup in a future post.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dNLSR5-2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76172689-62b14580-61d3-11ea-8dd5-26fb9c1f4d40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dNLSR5-2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76172689-62b14580-61d3-11ea-8dd5-26fb9c1f4d40.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Local Simulator
&lt;/h3&gt;

&lt;h5&gt;
  
  
  A simulated local environment using the &lt;a href="https://github.com/Azure/iotedgehubdev"&gt;Azure IoT Edge Hub Development simulator to run against the IOT Hub.&lt;/a&gt;   When developing for the edge it is recommended &lt;span&gt;not&lt;/span&gt; to install &lt;a href="https://docs.microsoft.com/bs-latn-ba/Azure/iot-edge/how-to-install-iot-edge-linux"&gt;the real ‘IOT edge runtime’&lt;/a&gt; on your machine but instead use the simulator.
&lt;/h5&gt;

&lt;h3&gt;
  
  
  2. Local Device
&lt;/h3&gt;

&lt;h5&gt;
  
  
  Linux Ubuntu machine hosted in VMWare on my local machine using Hyper V
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/bs-latn-ba/Azure/iot-edge/how-to-install-iot-edge-linux"&gt;https://docs.microsoft.com/bs-latn-ba/Azure/iot-edge/how-to-install-iot-edge-linux&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MhkPEUY_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76173281-1d901200-61d9-11ea-9a9c-bdceacf476c9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MhkPEUY_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76173281-1d901200-61d9-11ea-9a9c-bdceacf476c9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Cloud Device
&lt;/h3&gt;

&lt;h5&gt;
  
  
  Linux Ubuntu hosted on Azure in our resource group &lt;a href="https://github.com/chrismckelt/edgy/blob/master/scripts/environment/init.ps1"&gt;created using this script&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;This uses the pre-existing &lt;a href="https://azuremarketplace.microsoft.com/en-us/marketplace/apps/microsoft_iot_edge.iot_edge_vm_ubuntu?tab=overview"&gt;Linux Ubuntu image from the Azure Marketplace&lt;/a&gt;  with the runtime installed.&lt;/p&gt;

&lt;p&gt;Once up and running VS Code will show the devices below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://user-images.githubusercontent.com/662868/76172706-870d2200-61d3-11ea-8c02-eb29f5813075.png"&gt; &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--34jw1DpE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76172706-870d2200-61d3-11ea-8c02-eb29f5813075.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Outro
&lt;/h1&gt;

&lt;p&gt;Now we have a view of the setup, development environment &amp;amp; code, we can move onto the next post ‘Developing custom modules for Azure IoT Edge'&lt;/p&gt;

</description>
      <category>azure</category>
      <category>iot</category>
      <category>edge</category>
    </item>
    <item>
      <title>Using Azure Pipelines to restore a production database to another environment</title>
      <dc:creator>Chris McKelt</dc:creator>
      <pubDate>Wed, 28 Aug 2019 14:31:17 +0000</pubDate>
      <link>https://dev.to/chris_mckelt/using-azure-pipelines-to-restore-a-production-database-to-another-environment-51lo</link>
      <guid>https://dev.to/chris_mckelt/using-azure-pipelines-to-restore-a-production-database-to-another-environment-51lo</guid>
      <description>&lt;p&gt;Often we need a fresh copy of the production database in another environment (eg DEV/TEST/UAT). &lt;/p&gt;

&lt;p&gt;Previously this was a tedious task involving getting a backup file, copying it to another location, restoring the database.   Here is a solution to automate this process using Azure Pipelines.&lt;/p&gt;

&lt;h3&gt;
  
  
  User Story
&lt;/h3&gt;

&lt;p&gt;Given a production database exists in &lt;u&gt;subscription 1&lt;/u&gt;  &lt;/p&gt;

&lt;p&gt;When we do a release of the Azure Pipeline named ‘&lt;em&gt;Refresh Database – DEV’&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;Then an copy of production is available in the DEV environment in &lt;u&gt;subscription 2&lt;/u&gt;  &lt;/p&gt;

&lt;p&gt;And permissions are correct for the DEV environment&lt;/p&gt;

&lt;h2&gt;
  
  
  Pipeline Overview
&lt;/h2&gt;

&lt;p&gt;For each environment that you wish to restore into create an Azure Pipeline with 3 stages.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2019/08/image-7.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fblog.mckelt.com%2Fwp-content%2Fuploads%2F2019%2F08%2Fimage_thumb-7.png" title="image" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create variable groups that are &lt;strong&gt;scoped to specific stages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each variable group contains deployment credentials that the specific stage will require to perform operations within the &lt;u&gt;specific&lt;/u&gt; Azure Subscription.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2019/08/image-8.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fblog.mckelt.com%2Fwp-content%2Fuploads%2F2019%2F08%2Fimage_thumb-8.png" title="image" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Task 1 – Export
&lt;/h3&gt;

&lt;p&gt;Create a PowerShell task to run a script and pass it the information for the production environment.&lt;/p&gt;

&lt;p&gt;This runs against the production environment and creates a blog storage container that holds the exported BACPAC&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2019/08/image-9.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fblog.mckelt.com%2Fwp-content%2Fuploads%2F2019%2F08%2Fimage_thumb-9.png" title="image" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;a href="https://gist.github.com/chrismckelt/cc3c2ea53d8500b7c02e3da43513cbae" rel="noopener noreferrer"&gt;View code for script production-export.ps1&lt;/a&gt;
&lt;/h6&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Results in production once this script run should show the database BACPAC export
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;a href="http://blog.mckelt.com/wp-content/uploads/2019/08/image-10.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fblog.mckelt.com%2Fwp-content%2Fuploads%2F2019%2F08%2Fimage_thumb-10.png" title="image" alt="image"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Task 2 – Import
&lt;/h3&gt;

&lt;p&gt;Under the ‘import’ stage create a task that will import the BACPAC from the storage container in the production subscription.  This uses both production and the environment credentials.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2019/08/image-11.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fblog.mckelt.com%2Fwp-content%2Fuploads%2F2019%2F08%2Fimage_thumb-11.png" title="image" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;a href="https://gist.github.com/chrismckelt/629f992935f9a6aa6701e2c69ae49358" rel="noopener noreferrer"&gt;View code for script production-import.ps1&lt;/a&gt;
&lt;/h6&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Task 3 – Sanitise
&lt;/h3&gt;

&lt;p&gt;Create a 3rd task in the ‘Sanitise’ stage. &lt;/p&gt;

&lt;p&gt;This will scramble any  information you do not want in that environment (eg emails).&lt;/p&gt;

&lt;p&gt;Also remove any Production SQL user account and replace them with environment specific&lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;a href="https://gist.github.com/chrismckelt/f1dcefb52db6e79b8e5514853067e774" rel="noopener noreferrer"&gt;View code for script sanitise&lt;/a&gt;
&lt;/h6&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;h2&gt;
  
  
  TADA!
&lt;/h2&gt;

&lt;p&gt;Running the pipeline now copies the database to the DEV environment. Typically after this will run a software build which will automatically apply schema changes currently in DEV in the database. Happy restoring!&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.mckelt.com/wp-content/uploads/2019/08/image-13.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fblog.mckelt.com%2Fwp-content%2Fuploads%2F2019%2F08%2Fimage_thumb-13.png" title="image" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>azure</category>
      <category>cloud</category>
      <category>azuredevops</category>
      <category>devops</category>
    </item>
    <item>
      <title>NDepend code analysis</title>
      <dc:creator>Chris McKelt</dc:creator>
      <pubDate>Tue, 02 Jul 2019 02:31:53 +0000</pubDate>
      <link>https://dev.to/chris_mckelt/ndepend-code-analysis-415a</link>
      <guid>https://dev.to/chris_mckelt/ndepend-code-analysis-415a</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Recently I was asked to inspect and old VB.Net Windows Forms &amp;amp; SQL Server application to see determine its future life.  Part of this technical review was analysing the code base and database structure.&lt;/p&gt;

&lt;p&gt;To analyse the code base I used &lt;a href="https://www.ndepend.com/"&gt;NDepend&lt;/a&gt; a well-known code quality analysis tool that has progressed by &lt;a href="https://www.ndepend.com/release-notes"&gt;leaps and bounds&lt;/a&gt; since I last used it on the build server circa 2013 (then version 5).  Now on version &lt;a href="https://www.ndepend.com/release-notes#V2019_2_4"&gt;2019.2.4&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Application Overview
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  .Net 4.6 Windows Forms&lt;/li&gt;
&lt;li&gt;  SQL Server database where most of the logic resides (some in the GUI)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0u1EBHji--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76383664-7f967600-6397-11ea-8a88-09dd02fa4f82.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0u1EBHji--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76383664-7f967600-6397-11ea-8a88-09dd02fa4f82.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;After installing NDepend you will get a menu icon in Visual Studio&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2C0MqXvN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76383668-858c5700-6397-11ea-80bb-966b0214ef1a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2C0MqXvN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76383668-858c5700-6397-11ea-80bb-966b0214ef1a.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next setup the NDepend project for analysis.  Within Visual Studio I select the projects and references I wish to include in the analysis.  I am also able to include 2 extra DLLs that the vendor bundled with the application (but did not provide the source code)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lw71pzwU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76383673-8ae9a180-6397-11ea-97b9-8aa63b15ca76.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lw71pzwU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76383673-8ae9a180-6397-11ea-97b9-8aa63b15ca76.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next tab I setup the Analysis settings and output location.   This will enable NDepend to perform a time-based analysis to see how the solution has progressed/regressed since the last analysis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HYeREJcb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76383809-fe8bae80-6397-11ea-80d4-79170f6da4d3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HYeREJcb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76383809-fe8bae80-6397-11ea-80d4-79170f6da4d3.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the Analysis
&lt;/h2&gt;

&lt;p&gt;The analysis tool may be run and viewed from inside Visual Studio or output as a HTML file (great for the build server report).&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Metrics
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g8_nlbJg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76384667-88d51200-639a-11ea-8e1e-c72c9e3abb1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g8_nlbJg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76384667-88d51200-639a-11ea-8e1e-c72c9e3abb1b.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Quality Gates
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YlqG7Ujz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76384677-912d4d00-639a-11ea-86ba-c2b4b208b876.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YlqG7Ujz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76384677-912d4d00-639a-11ea-86ba-c2b4b208b876.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Graph
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j6p6Z5-K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76384692-9c807880-639a-11ea-9bd3-8f8d67a32200.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j6p6Z5-K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76384692-9c807880-639a-11ea-9bd3-8f8d67a32200.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependence Matrix
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Dj-7fUo2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76384954-5f68b600-639b-11ea-890c-c399af02a0f1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dj-7fUo2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76384954-5f68b600-639b-11ea-890c-c399af02a0f1.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cyclomatic Complexity
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cyclomatic complexity&lt;/strong&gt; is a &lt;a href="https://en.wikipedia.org/wiki/Software_metric"&gt;software metric&lt;/a&gt; used to indicate the complexity of a program. It is a quantitative measure of the number of linearly independent paths through a program's &lt;a href="https://en.wikipedia.org/wiki/Source_code"&gt;source code&lt;/a&gt;. It was developed by &lt;a href="https://en.wikipedia.org/w/index.php?title=Thomas_J._McCabe,_Sr.&amp;amp;action=edit&amp;amp;redlink=1"&gt;Thomas J. McCabe, Sr.&lt;/a&gt; in 1976.&lt;/p&gt;

&lt;p&gt;Cyclomatic complexity is computed using the &lt;a href="https://en.wikipedia.org/wiki/Control_flow_graph"&gt;control flow graph&lt;/a&gt; of the program: the nodes of the &lt;a href="https://en.wikipedia.org/wiki/Graph_(discrete_mathematics)"&gt;graph&lt;/a&gt; correspond to indivisible groups of commands of a program, and a &lt;a href="https://en.wikipedia.org/wiki/Directed_graph"&gt;directed&lt;/a&gt; edge connects two nodes if the second command might be executed immediately after the first command. Cyclomatic complexity may also be applied to individual &lt;a href="https://en.wikipedia.org/wiki/Function_(computer_science)"&gt;functions&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Modular_programming"&gt;modules&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Method_(computer_science)"&gt;methods&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Class_(computer_science)"&gt;classes&lt;/a&gt; within a program.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n5JlQ6mL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76384702-a4d8b380-639a-11ea-9fa8-a1121ba1e34f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n5JlQ6mL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76384702-a4d8b380-639a-11ea-9fa8-a1121ba1e34f.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;KEY AREAS TO REDUCE COMPLEXITY ARE&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  CPS.UI.ProjectDataSetTableAdapters – code that handles retrieving/saving projects&lt;/li&gt;
&lt;li&gt;  CPS.UI.AdminDataSetTableAdapters – code that handles retrieving/saving admin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ideally remove the use of data sets/adapters as a data access pattern and move to a modern-day best practice solution (entity framework, dapper).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Abstractness versus Instability Diagram
&lt;/h3&gt;

&lt;p&gt;The Abstractness versus Instability Diagram helps to detect which assemblies are potentially painful to maintain (i.e concrete and stable) and which assemblies are potentially useless (i.e abstract and instable).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Abstractness: If an assembly contains many abstract types (i.e interfaces and abstract classes) and few concrete types, it is considered as abstract.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Instability: An assembly is considered stable if its types are used by a lot of types from other assemblies. In this context stable means painful to modify.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Online documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.ndepend.com/docs/code-metrics#MetricsOnAssemblies"&gt;Definitions of related Code Metrics&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--olLYqZx5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76385021-950d9f00-639b-11ea-93b4-9f577f7cc6d4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--olLYqZx5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/662868/76385021-950d9f00-639b-11ea-93b4-9f577f7cc6d4.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Outro
&lt;/h2&gt;

&lt;p&gt;This post is a Work in Progress – stay tuned as I update it over time and determine the best use for NDepend as I have requested changes by the Vendor to fix areas of the code.  NDepend will be the tool I use that helps me guide the vendors code quality.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>ndepend</category>
      <category>codeanalysis</category>
    </item>
    <item>
      <title>Reactive architecture with event grid</title>
      <dc:creator>Chris McKelt</dc:creator>
      <pubDate>Sat, 27 Apr 2019 04:59:11 +0000</pubDate>
      <link>https://dev.to/chris_mckelt/reactive-architecture-with-event-grid-3ab5</link>
      <guid>https://dev.to/chris_mckelt/reactive-architecture-with-event-grid-3ab5</guid>
      <description>&lt;p&gt;Azure Global Bootcamp – 27th April 2019&lt;/p&gt;

&lt;p&gt;&lt;a href="/wp-content/uploads/2019/04/image.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmckeltblog.azurewebsites.net%2Fwp-content%2Fuploads%2F2019%2F04%2Fimage_thumb.png" title="image" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsecure.meetupstatic.com%2Fphotos%2Fevent%2Fc%2F7%2F2%2Fc%2Fhighres_480710988.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsecure.meetupstatic.com%2Fphotos%2Fevent%2Fc%2F7%2F2%2Fc%2Fhighres_480710988.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;a href="https://www.dropbox.com/s/vs30gyesyqwmz72/azure-global-bootcamp-event-grid-2019.pdf?dl=0" rel="noopener noreferrer"&gt;Click here to view slides&lt;/a&gt;
&lt;/h1&gt;

</description>
      <category>dotnet</category>
      <category>azure</category>
      <category>eventgrid</category>
      <category>d365</category>
    </item>
    <item>
      <title>Predicting BS using ML.Net</title>
      <dc:creator>Chris McKelt</dc:creator>
      <pubDate>Wed, 08 Aug 2018 02:48:33 +0000</pubDate>
      <link>https://dev.to/chris_mckelt/predicting-bs-using-ml-net-5hen</link>
      <guid>https://dev.to/chris_mckelt/predicting-bs-using-ml-net-5hen</guid>
      <description>&lt;h1&gt;
  
  
  Predicting BS using ML.Net
&lt;/h1&gt;

&lt;p&gt;Machine learning is typically the realm for R/Python. But can .Net move into this space?&lt;/p&gt;

&lt;p&gt;In this talk we will run through Microsoft’s new ML.Net framework including what it currently offers, how to build a learning pipeline and how to deploy a model to an Azure Service.&lt;/p&gt;

&lt;p&gt;&lt;a href="/wp-content/uploads/2018/08/image-7.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmckeltblog.azurewebsites.net%2Fwp-content%2Fuploads%2F2018%2F08%2Fimage_thumb-7.png" title="image" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://slides.com/chrismckelt/deck-451cdb94-a37d-47b7-9d49-6686065e7d03" rel="noopener noreferrer"&gt;https://slides.com/chrismckelt/deck-451cdb94-a37d-47b7-9d49-6686065e7d03&lt;/a&gt;&lt;/p&gt;

</description>
      <category>net</category>
      <category>chargeid</category>
      <category>machinelearning</category>
      <category>mlnet</category>
    </item>
  </channel>
</rss>
