<?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: Peter Eysermans</title>
    <description>The latest articles on DEV Community by Peter Eysermans (@petereysermans).</description>
    <link>https://dev.to/petereysermans</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%2F5845%2Fac59a467-1a7e-4b35-a799-7f976374c8ab.jpeg</url>
      <title>DEV Community: Peter Eysermans</title>
      <link>https://dev.to/petereysermans</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/petereysermans"/>
    <language>en</language>
    <item>
      <title>Creating an iOS 14 widget showing health data</title>
      <dc:creator>Peter Eysermans</dc:creator>
      <pubDate>Sun, 19 Jul 2020 10:40:46 +0000</pubDate>
      <link>https://dev.to/petereysermans/creating-an-ios-14-widget-showing-health-data-1m4o</link>
      <guid>https://dev.to/petereysermans/creating-an-ios-14-widget-showing-health-data-1m4o</guid>
      <description>&lt;p&gt;With iOS 14 Apple introduced a neat new feature: widgets. I've been running the beta for some weeks now and love them. So let's see how hard it is to create one ourself.&lt;/p&gt;

&lt;p&gt;Let's start with a little disclaimer: This article and the code with it was written using iOS 14 beta 2 and Xcode 12 beta 2. There is no guarantee that it will work in future versions.&lt;/p&gt;

&lt;p&gt;Via the health app in iOS you can track your sleep with either your iPhone or your Apple Watch. I thought it would be neat to have a widget which shows the time you slept last night. Let's look at the end result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/end-result.png"&gt;&lt;img alt="App with widget that shows health data" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hv1pnUJU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/end-result.png" width="800" height="1732"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first thing you need to know when developing a widget: your widget won't work if the code you are using in your widget is not being called in the app itself as well. At first I struggled with this. If your widget contains code that is not called by the app, it won't work. With this in mind let's first develop the main app and once it's finished we can reuse part of its code to create a widget for it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Configuring HealthKit
&lt;/h1&gt;

&lt;p&gt;First some setup needs to be done. The app needs permission to query data from the iOS Health app. In the Project navigator, select the top most item in the list and open the &lt;code&gt;Signing &amp;amp; Capabilities&lt;/code&gt; tab. Add a capability by clicking on the &lt;code&gt;+ Capability&lt;/code&gt; button on the top left. In the popup that follows select the &lt;code&gt;HealthKit&lt;/code&gt; capability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/add-healthkit-capability.png"&gt;&lt;img alt="Add HealthKit capability" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ruOdemQs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/add-healthkit-capability.png" width="800" height="613"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next to this capability we also need to add two rows to the &lt;code&gt;Info.plist&lt;/code&gt; file to explain to the user what will happen with the data. Open the file and add these two rows to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Privacy - Health Share Usage Description&lt;/li&gt;
&lt;li&gt;Privacy - Health Update Usage Description&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Give a description what your app will be doing with the data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/health-in-info-plist.png"&gt;&lt;img alt="Health Info.plist rows" src="https://res.cloudinary.com/practicaldev/image/fetch/s--h8rxKXuo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/health-in-info-plist.png" width="800" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Fetching sleep data
&lt;/h1&gt;

&lt;p&gt;Now the app is all set up to read the necessary data from the Health app. To fetch this data a helper class is created, this helper class will be reused when the widget is created. The code to retrieve the sleep data is based on code from &lt;a href="https://www.appcoda.com/sleep-analysis-healthkit/"&gt;this article: Using Sleep Analysis in HealthKit with Swift&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To interact with the Health app &lt;code&gt;HealthKit&lt;/code&gt; is imported and the HealthKit &lt;code&gt;HKHealthStore&lt;/code&gt; class is used. Before data can be read, the app needs authorisation to query data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;retrieveSleepWithAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;typestoRead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="kt"&gt;HKObjectType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;categoryType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forIdentifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;HKCategoryTypeIdentifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleepAnalysis&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
        &lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;typestoShare&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="kt"&gt;HKObjectType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;categoryType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forIdentifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;HKCategoryTypeIdentifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleepAnalysis&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
        &lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="n"&gt;healthStore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestAuthorization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;toShare&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;typestoShare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;typestoRead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;NSLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" Display not allowed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieveSleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function doesn't need much explanation, the type of data the app will save and read are passed to the &lt;code&gt;healthStore&lt;/code&gt; via the &lt;code&gt;requestAuthorization&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Once the authorisation has been approved, the sleep data can be fetched. Because the app only shows the data from last night, the data is filtered using a predicate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;startDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Calendar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;byAdding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;endDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;predicate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;HKQuery&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predicateForSamples&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;withStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;endDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;HKQueryOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strictEndDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see the predicate filters all data from yesterday until today. Now that there is a predicate, we can query the &lt;code&gt;healthStore&lt;/code&gt; to get the necessary data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sleepType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;HKObjectType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;categoryType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forIdentifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;HKCategoryTypeIdentifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleepAnalysis&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sortDescriptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NSSortDescriptor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;HKSampleSortIdentifierEndDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;ascending&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

     &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;HKSampleQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sampleType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sleepType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;sortDescriptors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sortDescriptor&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tmpResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;

     &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;healthStore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things are happening in this block of code. The &lt;code&gt;sleepType&lt;/code&gt; variable indicates the type of data that is fetched, the &lt;code&gt;sortDescriptor&lt;/code&gt; describes how the data should be sorted. In this case the newest data is on top. At last a query object is created using the type, predicate and sort descriptor. It has a closure where the fetched data can be processed. This query is passed to the &lt;code&gt;healthStore&lt;/code&gt; instance and that's it.&lt;/p&gt;

&lt;p&gt;In the closure the number of seconds between the start and end of each sleep session is calculated and the total number of seconds is converted to a readable format: &lt;code&gt;7h 30m 4s&lt;/code&gt;. This is the query object including the closure for the sake of being complete:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;HKSampleQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sampleType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sleepType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;sortDescriptors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sortDescriptor&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tmpResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;totalSeconds&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tmpResult&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;HKCategorySample&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

                  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;timeInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeIntervalSince&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                  &lt;span class="n"&gt;totalSeconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;totalSeconds&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;timeInterval&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;totalSeconds&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"h "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
          &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;totalSeconds&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;truncatingRemainder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dividingBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"m "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
          &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;totalSeconds&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;truncatingRemainder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dividingBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;truncatingRemainder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dividingBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"s"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Showing sleep data
&lt;/h1&gt;

&lt;p&gt;Now that the necessary data is fetched, it can be shown in the UI. This &lt;code&gt;ObservableObject&lt;/code&gt; will be used to drive the UI. It has a &lt;code&gt;mainText&lt;/code&gt; property in which the fetched sleep data is filled out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;SleepModel&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;mainText&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Getting your sleep time from yesterday"&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sleepRetrieval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SleepRetrieval&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;retrieveSleep&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;sleepRetrieval&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieveSleepWithAuth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mainText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is the SwiftUI view to show the data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ContentView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;@ObservedObject&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;viewModel&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SleepModel&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="kt"&gt;VStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;alignment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Last night you slept: "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;// show the text from the SleepModel in the UI&lt;/span&gt;
            &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mainText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="c1"&gt;// when the text appears call the SleepModel to fetch the necessary data&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onAppear&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieveSleep&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;minWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;minHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;maxHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;infinity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;background&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;LinearGradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="nv"&gt;startPoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;endPoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="c1"&gt;// stretch the gradient from top to bottom, ignoring the safe area&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;edgesIgnoringSafeArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the app, this is the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/app-functionality.png"&gt;&lt;img alt="App showing health data" src="https://res.cloudinary.com/practicaldev/image/fetch/s--0HSnOZqA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/app-functionality.png" width="800" height="1732"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Widget
&lt;/h1&gt;

&lt;p&gt;Now that the basic functionality has been implemented in the app, let's &lt;a href="https://swiftrocks.com/ios-14-widget-tutorial-mini-apps"&gt;create a widget for it&lt;/a&gt;. This allows the user to see how much he has slept last night without having to open the app itself. To create a widget for an app, add a new target to the project in Xcode via &lt;code&gt;File &amp;gt; New &amp;gt; Target...&lt;/code&gt;. In the popup select &lt;code&gt;Widget extension&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/add-widget-extension-target.png"&gt;&lt;img alt="Add widget extension target" src="https://res.cloudinary.com/practicaldev/image/fetch/s--idOUOHho--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/add-widget-extension-target.png" width="800" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to the next window, give the widget a name and uncheck the &lt;code&gt;Include Configuration Intent&lt;/code&gt;. This checkbox is intended if the widget has certain properties than can be configured by the user and is out of scope for this little project. When finishing the wizard there should be a new folder in the Project navigator in Xcode with the name of the widget you have chosen. In there Xcode has generate several files to create the widget.&lt;/p&gt;

&lt;p&gt;This widget has its own plist file. The first thing that needs to happen, in order to allow the widget to read data from the Health app, is to add the necessary rows to the &lt;code&gt;Info.plist&lt;/code&gt; file of the widget similar to what has been done for the app itself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/health-in-info-plist.png"&gt;&lt;img alt="Health Info.plist rows" src="https://res.cloudinary.com/practicaldev/image/fetch/s--h8rxKXuo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/health-in-info-plist.png" width="800" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The class where it all starts is the one annotated with the &lt;code&gt;@main&lt;/code&gt;. That is the starting point for the widget.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@main&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;SleepTrackerWidget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Widget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SleepTrackerWidget"&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;WidgetConfiguration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;StaticConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SleepTimeline&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PlaceholderView&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="kt"&gt;SleepTrackerWidgetEntryView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configurationDisplayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Time slept"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This widget shows the time you slept last night."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The widget uses a &lt;a href="https://developer.apple.com/documentation/widgetkit/staticconfiguration"&gt;&lt;code&gt;StaticConfiguration&lt;/code&gt;&lt;/a&gt; because the widget has no user configurable options. To this instance a &lt;code&gt;TimelineProvider&lt;/code&gt;, a &lt;code&gt;PlaceholderView&lt;/code&gt; and a closure with an &lt;code&gt;entry&lt;/code&gt; instance that has the necessary data for the widget to display are passed.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;configurationDisplayName&lt;/code&gt; and the &lt;code&gt;description&lt;/code&gt; are shown when the user is configuring his homescreen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/add-widget-window.png"&gt;&lt;img alt="Add widget window" src="https://res.cloudinary.com/practicaldev/image/fetch/s--JnMv14tt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/add-widget-window.png" width="800" height="1732"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's have a look at the &lt;code&gt;TimelineProvider&lt;/code&gt;. The class provides two methods that need to be overriden. The &lt;a href="https://developer.apple.com/documentation/widgetkit/timelineprovider/snapshot(with:completion:)?changes=latest___6_2"&gt;&lt;code&gt;snapshot&lt;/code&gt;&lt;/a&gt; method is called by WidgetKit whenever the widget is in a transient state. For example when it appears in the widget gallery. Some sample data can be provided to give the user an idea of what the widget does an how it looks.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://developer.apple.com/documentation/widgetkit/timelineprovider/timeline(with:completion:)"&gt;&lt;code&gt;timeline&lt;/code&gt;&lt;/a&gt; method is where it happens. This will be called by WidgetKit every time the widget needs to be updated. The time the widget needs to be updated is controlled by the &lt;code&gt;refreshDate&lt;/code&gt; that is passed to the &lt;code&gt;Timeline&lt;/code&gt; instance. This code tells WidgetKit to update the widget every day. It does not guarantee that the widget will be updated at that moment. iOS still decides itself when it updates the widget and takes other parameters into account, for example if the widget is currently not on the screen it could decide to wait with updating the widget. The helper class to retrieve the sleep is used and in the closure an entry is created and passed to the &lt;code&gt;completion&lt;/code&gt; closure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;SleepTimeline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimelineProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;SleepEntry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SleepEntry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;timeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Timeline&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;currentDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;refreshDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Calendar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;byAdding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;currentDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

        &lt;span class="kt"&gt;SleepRetrieval&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;retrieveSleep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;

            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SleepEntry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;currentDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;timeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Timeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;refreshDate&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="nf"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To be able to use the helper class, don't forget to check the widget extension in the &lt;code&gt;Target Membership&lt;/code&gt; in Xcode.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/target-membership.png"&gt;&lt;img alt="Add widget window" src="https://res.cloudinary.com/practicaldev/image/fetch/s--XzoML22c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/target-membership.png" width="520" height="1076"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another important notice is that compared to the app itself this code will not ask permission to access the data of the Health app. This is because the widget cannot show the permission dialog. The error below is thrown when the widget tries to ask permission. &lt;a href="https://developer.apple.com/forums/thread/653814"&gt;More information can be found in this thread on the Apple developer forums.&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mo"&gt;07&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;02&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;27.315405&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mo"&gt;0200&lt;/span&gt; &lt;span class="kt"&gt;SleepTrackerWidgetExtension&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9097&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2633778&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kt"&gt;FAILED&lt;/span&gt; &lt;span class="n"&gt;prompting&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nf"&gt;share&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kt"&gt;HKCategoryTypeIdentifierSleepAnalysis&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;read&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kt"&gt;HKCategoryTypeIdentifierSleepAnalysis&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mo"&gt;07&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;02&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;27.315675&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mo"&gt;0200&lt;/span&gt; &lt;span class="kt"&gt;SleepTrackerWidgetExtension&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9097&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2633778&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="kt"&gt;Display&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;allowed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The solution is to handle the permission in the app itself and just retrieve the necessary data in the widget.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;SleepEntry&lt;/code&gt; class is the ViewModel which is used to pass the data to the widget.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;SleepEntry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimelineEntry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Date&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last thing that needs to be defined is the user interface. There are two classes that are responsible for how the widget looks. The &lt;code&gt;PlaceholderView&lt;/code&gt; is the class that is used when the widget is shown for the first time. From the Apple documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's a generic visual representation with no specific content.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;SleepTrackerWidgetEntryView&lt;/code&gt; is the main class that provides the user interface. It has a &lt;code&gt;Timeline.Entry&lt;/code&gt; property which is actually an instance of the &lt;code&gt;SleepEntry&lt;/code&gt; class, it contains the necessary data for the widget to show.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;SleepTrackerWidgetEntryView&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SleepTimeline&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Entry&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;VStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;alignment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You slept:"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;minWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;minHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;maxHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;infinity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;background&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;LinearGradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="nv"&gt;startPoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;endPoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it, our app now has a neat widget. Let's look at the end result one more time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/end-result.png"&gt;&lt;img alt="App with widget that shows health data" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hv1pnUJU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/creating-an-ios-14-widget-showing-health-data/end-result.png" width="800" height="1732"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you need the full project, the code can be &lt;a href="https://github.com/petereysermans/sleeptracker"&gt;found on github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>widget</category>
      <category>health</category>
      <category>swift</category>
    </item>
    <item>
      <title>Manipulating an Excel file with Python</title>
      <dc:creator>Peter Eysermans</dc:creator>
      <pubDate>Fri, 15 May 2020 21:04:01 +0000</pubDate>
      <link>https://dev.to/petereysermans/manipulating-an-excel-file-with-python-1595</link>
      <guid>https://dev.to/petereysermans/manipulating-an-excel-file-with-python-1595</guid>
      <description>&lt;p&gt;It's one of those things that sound easy but hardly are. There are a lot of libraries and solutions out there that enable you to manipulate Excel files via code. Some of them are expensive, other are open source.&lt;/p&gt;

&lt;p&gt;A lot of languages have a library to help you manipulate Excel files. An obvious language to choose is C#. It has a lot of options, some open source, some paying. Instead of using C#, I opted for Python. Unlike C#, Python is very light weight to start with and does not need a big IDE like Visual Studio to create a small application.&lt;/p&gt;

&lt;p&gt;In Python there are multiple options to use. &lt;a href="https://pandas.pydata.org/"&gt;Pandas&lt;/a&gt; and &lt;a href="https://xlsxwriter.readthedocs.io/"&gt;xlsxwriter&lt;/a&gt; can both write to an Excel file but they both have their limitations as well. Xlsxwriter can only create new Excel files and Pandas does not have the functionality to export a sheet of the Excel file to PDF. So I opted in using the &lt;a href="https://docs.microsoft.com/en-us/office/vba/api/overview/excel/object-model"&gt;Excel COM Object&lt;/a&gt; that ships with Excel.&lt;/p&gt;

&lt;p&gt;This comes with some prerequisites, the code will only work on Windows with Excel installed. There is a package to use COM objects called &lt;code&gt;pywin32&lt;/code&gt;. It's a bit confusing, there are actually two packages, &lt;code&gt;pywin32&lt;/code&gt; and &lt;code&gt;pypiwin32&lt;/code&gt;. But &lt;a href="https://stackoverflow.com/questions/55918311/what-is-the-difference-between-pywin32-and-pypiwin32"&gt;&lt;code&gt;pypiwin32&lt;/code&gt; is abandoned an the &lt;code&gt;pywin32&lt;/code&gt; package is the way to go&lt;/a&gt;. It's installed via &lt;code&gt;pip&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pywin32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing the package, the code is fairly easy. First let's create an application, this is the main object which allows to manipulate the Excel file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;win32com&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;

&lt;span class="n"&gt;excelApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Excel.Application"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next let's load an excel file to manipulate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;books&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;excelApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Workbooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s"&gt;"C:\\folder\\test.xlsx"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Writing a value to Excel
&lt;/h1&gt;

&lt;p&gt;Now everything is in place to read or write to the Excel file, to discover the possibilities you can always check the &lt;a href="https://docs.microsoft.com/en-us/visualstudio/vsto/excel-object-model-overview?redirectedfrom=MSDN](https://docs.microsoft.com/en-us/visualstudio/vsto/excel-object-model-overview?redirectedfrom=MSDN)"&gt;COM object documentation&lt;/a&gt;. Let's write a value to the Excel file and save it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;win32com&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;

&lt;span class="n"&gt;excelApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Excel.Application"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;excelApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Workbooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s"&gt;"C:\\folder\\test.xlsx"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;workSheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Worksheets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Sheet1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;workSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cells&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"test"&lt;/span&gt;

&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code will write the value &lt;code&gt;test&lt;/code&gt; to the cell A1 in the Excel file. Notice that the &lt;code&gt;Cells&lt;/code&gt; property has a 1-based index for both the row and the column.&lt;/p&gt;

&lt;h1&gt;
  
  
  Generating a PDF from the Excel file
&lt;/h1&gt;

&lt;p&gt;There are not a lot of libraries out there that foresee in this functionality. Using Python and the Excel COM object is one of the easiest ways to generate a PDF from an Excel file. I've used this on big Excel files and achieved very good results with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;win32com&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;

&lt;span class="n"&gt;excelApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Excel.Application"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;excelApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Workbooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s"&gt;"C:\\folder\\test.xlsx"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;sheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Worksheets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Sheet1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExportAsFixedFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s"&gt;"C:\\folder\\test.pdf"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ExportAsFixedFormat&lt;/code&gt; is the method that does all the work. The first parameter is the type of format and is based on the &lt;a href="https://docs.microsoft.com/en-us/office/vba/api/excel.xlfixedformattype"&gt;&lt;code&gt;XlFixedFormatType&lt;/code&gt; enum&lt;/a&gt;. The PDF will be created on the destination that is specified as second parameter.&lt;/p&gt;

&lt;h1&gt;
  
  
  Performance
&lt;/h1&gt;

&lt;p&gt;When the use case gets more complex you often bump into performance problems. Here are a few tips that can help you. The first and most obvious tip is to get rid of all the unused functions in your Excel file, make your Excel file as simple as possible and make sure it has no unused formulas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disable display alerts
&lt;/h2&gt;

&lt;p&gt;To avoid Excel being blocked by an alert that could be shown to the user we can disable display alerts. If the Excel manipulation happens in the background the alerts won't be visible anyway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;win32com.client&lt;/span&gt;

&lt;span class="n"&gt;excelApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;win32com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Excel.Application"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;excelApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayAlerts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  XLSB file type
&lt;/h2&gt;

&lt;p&gt;Saving the Excel as the XSLB binary file type instead of the XLSX xml file type will give a small performance boost and make the file smaller.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/manipulating-an-excel-file-with-python/save_as_xslb.png"&gt;&lt;img alt="Save As XSLB" src="https://res.cloudinary.com/practicaldev/image/fetch/s--jScNeJgi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/manipulating-an-excel-file-with-python/save_as_xslb.png" width="800" height="644"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Compress images
&lt;/h2&gt;

&lt;p&gt;To make the Excel file as small as possible, the images that it contains can be compressed. Go to &lt;code&gt;File &amp;gt; Save As&lt;/code&gt; and open the &lt;code&gt;Compress Pictures&lt;/code&gt; option via &lt;code&gt;Tools&lt;/code&gt;. Choosing a higher compression will result in a smaller file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/manipulating-an-excel-file-with-python/range_test_1.png"&gt;&lt;img alt="Save As Compress Pictures Dialog" src="https://res.cloudinary.com/practicaldev/image/fetch/s--kTcvN8UO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/manipulating-an-excel-file-with-python/save_as_compress_pictures.png" width="800" height="642"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/manipulating-an-excel-file-with-python/range_test_1.png"&gt;&lt;img alt="Save As Compress Pictures Dialog" src="https://res.cloudinary.com/practicaldev/image/fetch/s--zqTr8_RG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/manipulating-an-excel-file-with-python/save_as_compress_pictures_dialog.png" width="800" height="685"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading and writing values using &lt;code&gt;Range&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Instead of using the &lt;code&gt;Cells&lt;/code&gt; property to write values one by one, it's also possible to write an entire range to the Excel file. This will be more performant than using &lt;code&gt;Cells&lt;/code&gt;. The value that is set to the Range is always an array of arrays. Let's start with a simple case&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;workSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'A1:A5'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will write values to the range &lt;code&gt;A1:A5&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/manipulating-an-excel-file-with-python/range_test_1.png"&gt;&lt;img alt="Write To Excel Using Range" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ofnuWKyh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/manipulating-an-excel-file-with-python/range_test_1.png" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To write to multiple columns a value can be added to the arrays for each column.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;workSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'A1:C5'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eysermans.com/images/articles/manipulating-an-excel-file-with-python/range_test_2.png"&gt;&lt;img alt="Write To Excel Using Range" src="https://res.cloudinary.com/practicaldev/image/fetch/s--rFdjuBrC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://eysermans.com/images/articles/manipulating-an-excel-file-with-python/range_test_2.png" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Disable automatic calculation
&lt;/h2&gt;

&lt;p&gt;If the Excel file you are using has a lot of formulas this might slow down the manipulation considerably. Because the formulas need to be recalculated every time a value changes in the Excel. This automatic recalculating can be disabled. This can be handy if you have a lot of values to fill out and if you are only interested in the end result. First you disable automatic recalculation, you fill out all the values and then you reenable automatic recalculation. This way the recalculation will only happen once even if a lot of values are filled out.&lt;/p&gt;

&lt;p&gt;This code will set the calculation to manual, the possible values of the &lt;code&gt;Calculation&lt;/code&gt; property can be found in the &lt;a href="https://docs.microsoft.com/en-us/office/vba/api/excel.xlcalculation"&gt;XlCalculation enumeration&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;win32com.client&lt;/span&gt;

&lt;span class="n"&gt;excelApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;win32com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Excel.Application"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;excelApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Calculation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4135&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To reenable the calculation set the &lt;code&gt;Calculation&lt;/code&gt; property to automatic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;excelApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Calculation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4105&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Turn off screen updating
&lt;/h2&gt;

&lt;p&gt;Turning off screen updating can also speed up the Excel manipulation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;win32com.client&lt;/span&gt;

&lt;span class="n"&gt;excelApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;win32com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Excel.Application"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;excelApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScreenUpdating&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Call rejected by callee
&lt;/h1&gt;

&lt;p&gt;This error can pop up sometimes, it usually happens when Excel is being called consecutive times and it is not fast enough to respond to the calls. Then it will return the error &lt;code&gt;Call rejected by callee&lt;/code&gt;. The solution is to retry the call whenever this error occurs, most of the time Excel will have finished with the current call and it will be able to handle the next one.&lt;/p&gt;

&lt;p&gt;To easily implement this I use a &lt;code&gt;ComWrapper&lt;/code&gt; class, the inspiration I got for this class comes from several &lt;a href="https://stackoverflow.com/questions/11249154/call-rejected-by-callee"&gt;Stackoverflow&lt;/a&gt; &lt;a href="https://stackoverflow.com/questions/54449520/call-was-rejected-by-callee-in-win32com-if-a-dialog-box-is-open-or-excel-is-othe/55892457#55892457"&gt;questions&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pywintypes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;com_error&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ComWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;staticmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;func_args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;func_args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;com_error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strerror&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'Call was rejected by callee.'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'com_error retrying '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;func_args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;raise&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class will wrap an existing method and when the pywin &lt;code&gt;com_error&lt;/code&gt; with the message &lt;code&gt;Call was rejected by callee.&lt;/code&gt; occurs it will wait for half a second and retry the same function with the same arguments.&lt;/p&gt;

&lt;p&gt;If we want to wrap writing a value to a cell, this is how it is done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;writeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;workSheet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rowNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;columnNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;workSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cells&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rowNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;columnNumber&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

&lt;span class="n"&gt;ComWrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writeValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;workSheet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First the property to set a certain value is wrapped in the &lt;code&gt;writeValue&lt;/code&gt; method. This way the method can be passed to the &lt;code&gt;ComWrapper&lt;/code&gt;. The first argument for the wrapper class is the method itself. Note that we are not calling that method, we pass it to the wrapper which will call it. Then all arguments that are normally passed to the method itself are passed to wrapper as well. The wrapper will retry the method call as long as the &lt;code&gt;Call was rejected by callee.&lt;/code&gt; error is thrown by Excel.&lt;/p&gt;

</description>
      <category>python</category>
      <category>excel</category>
      <category>automation</category>
      <category>windows</category>
    </item>
    <item>
      <title>Installing a node.js application as a Windows service</title>
      <dc:creator>Peter Eysermans</dc:creator>
      <pubDate>Sun, 12 Apr 2020 20:01:25 +0000</pubDate>
      <link>https://dev.to/petereysermans/installing-a-node-js-application-as-a-windows-service-28j7</link>
      <guid>https://dev.to/petereysermans/installing-a-node-js-application-as-a-windows-service-28j7</guid>
      <description>&lt;p&gt;It wasn't my intention when I started the first article but this has become a series of how to run node applications in production with IIS on Windows. These are the previous articles on the topic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://eysermans.com/post/hosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy" rel="noopener noreferrer"&gt;Hosting a Node.js application on Windows with IIS as reverse proxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eysermans.com/post/using-http-platform-handler-to-host-a-node-js-application-via-iis" rel="noopener noreferrer"&gt;Using HTTP platform handler to host a node.js application via IIS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the last article a node web application was deployed on a Windows server. With the help of the &lt;a href="https://www.iis.net/downloads/microsoft/httpplatformhandler" rel="noopener noreferrer"&gt;HTTP platform handler&lt;/a&gt;, IIS manages the node process for us. When it receives a request it will start the node process and pass the web request for node to handle it.&lt;/p&gt;

&lt;p&gt;In some cases however we don't want to expose the node.js web application via IIS. I have built an internal API in the past which should not be accessible from the outside for security reasons. The internal API is only consumed by other applications running on the same server. In this case, we can't rely on IIS to manage the node process for us as IIS would expose the web application to the internet.&lt;/p&gt;

&lt;p&gt;We need an alternative to keep the node process running to make the internal API available on the server via localhost. &lt;a href="https://pm2.keymetrics.io/" rel="noopener noreferrer"&gt;PM2&lt;/a&gt; can manage the node process and keep it up and running. Unfortunately I did not find a reliable way to start PM2 whenever the Windows Server restarts. Every time the server restarted, the internal API was down and had to be manually started.&lt;/p&gt;

&lt;p&gt;Luckily there is a &lt;a href="https://github.com/coreybutler/node-windows" rel="noopener noreferrer"&gt;NPM package &lt;code&gt;node-windows&lt;/code&gt;&lt;/a&gt; which can install a node application as a Windows service. This service can be automatically started when the server restarts.&lt;/p&gt;

&lt;p&gt;This is the Hello World sample from the Express website, we will install it as a Windows service:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) =&amp;gt; res.send('Hello World!'))

app.listen(port, () =&amp;gt; console.log(`Example app listening at http://localhost:${port}`))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;node-windows&lt;/code&gt; NPM package can do this for us. Run the following commands&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g node-windows
npm link node-windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once the package is installed it can be used to install the application as a service with the following node script:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var Service = require('node-windows').Service;

// Create a new service object
var svc = new Service({
  name:'Node application as Windows Service',
  description: 'Node application as Windows Service',
  script: 'C:\\temp\\test.js'
});

// Listen for the "install" event, which indicates the
// process is available as a service.
svc.on('install',function(){
  svc.start();
});

svc.install();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Just run the script as any other node script:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node install-windows-service.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If User Account Control (UAC) is enabled on Windows you will have to give permission a few times to complete the installation. Once this script has finished the service is installed and the application is running. You can find the service in the &lt;code&gt;Services&lt;/code&gt; dialog. It will have the name that you have passed to the &lt;code&gt;Service&lt;/code&gt; class in the node script.&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%2Feysermans.com%2Fimages%2Farticles%2Finstalling-a-node-application-as-a-windows-service%2Fservices.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%2Feysermans.com%2Fimages%2Farticles%2Finstalling-a-node-application-as-a-windows-service%2Fservices.png" alt="Services dialog with the newly installed Windows service"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the service ever needs to be uninstalled, the &lt;code&gt;Service&lt;/code&gt; class also has an &lt;code&gt;uninstall&lt;/code&gt; method:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var Service = require('node-windows').Service;

// Create a new service object
var svc = new Service({
  name:'Node application as Windows Service',
  description: 'Node application as Windows Service',
  script: 'C:\\temp\\test.js'
});

// Listen for the "uninstall" event so we know when it's done.
svc.on('uninstall',function(){
  console.log('Uninstall complete.');
  console.log('The service exists: ',svc.exists);
});

// Uninstall the service.
svc.uninstall();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This can also be run as any other node script:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node uninstall-windows.service.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Because the Windows service is set to start automatic, it will start every time the server is restarted. Exactly as expected. Happy deploying!&lt;/p&gt;

&lt;p&gt;This is a cross post from my &lt;a href="https://eysermans.com/post/installing-a-node-application-as-a-windows-service" rel="noopener noreferrer"&gt;own blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>windows</category>
      <category>node</category>
      <category>hosting</category>
      <category>service</category>
    </item>
    <item>
      <title>Using HTTP platform handler to host a node.js application via IIS</title>
      <dc:creator>Peter Eysermans</dc:creator>
      <pubDate>Fri, 13 Mar 2020 22:11:48 +0000</pubDate>
      <link>https://dev.to/petereysermans/using-http-platform-handler-to-host-a-node-js-application-via-iis-4pgd</link>
      <guid>https://dev.to/petereysermans/using-http-platform-handler-to-host-a-node-js-application-via-iis-4pgd</guid>
      <description>&lt;p&gt;About a year ago &lt;a href="https://eysermans.com/post/hosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy" rel="noopener noreferrer"&gt;I wrote about hosting a Node.js application via IIS&lt;/a&gt;. It uses IIS as a reversed proxy to route traffic from IIS to the node.js webserver. To manage the node.js process pm2 was used. Unfortunately I had some problems restarting the pm2 process when the server restarted. This meant downtime everytime the server was restarted until I manually resurrected pm2.&lt;/p&gt;

&lt;p&gt;The original post got a lot of comments and in one of them &lt;a href="https://dev.to/davidwhit/comment/ho9e"&gt;DavidWhit mentioned that the HTTP Platform handler can be used to manage the node.js process&lt;/a&gt;. This IIS module will manage a given process and proxy requests to the process it manages. It acts as a reverse proxy and it manages the process, it's even better than the &lt;a href="https://eysermans.com/post/hosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy" rel="noopener noreferrer"&gt;previous solution&lt;/a&gt;. It's not limited to node.js processes, it can manage any process. This also makes it a good solution to host Ruby or other platforms on Windows.&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%2Feysermans.com%2Fimages%2Farticles%2Fusing-http-platform-handler-to-host-a-node-js-application-via-iis%2Fdiagram.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%2Feysermans.com%2Fimages%2Farticles%2Fusing-http-platform-handler-to-host-a-node-js-application-via-iis%2Fdiagram.png" alt="HTTP platform handler schema"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am assuming you already have a node application running, if not please check the &lt;a href="https://eysermans.com/post/hosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy" rel="noopener noreferrer"&gt;previous post to create a simple hello world example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To install the module, &lt;a href="https://www.iis.net/downloads/microsoft/httpplatformhandler" rel="noopener noreferrer"&gt;download the installer&lt;/a&gt; and run it on your server. This module can only be configured using a web.config, there is no GUI element in the IIS Manager to configure it. Add a web.config in the root of the website if there isn't one yet and copy over this configuration.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;configuration&amp;gt;
  &amp;lt;system.webServer&amp;gt;
    &amp;lt;handlers&amp;gt;
      &amp;lt;add name="httppPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" /&amp;gt;
    &amp;lt;/handlers&amp;gt;
    &amp;lt;httpPlatform stdoutLogEnabled="true" stdoutLogFile=".\node.log" startupTimeLimit="20" processPath="C:\Program Files\nodejs\node.exe" arguments=".\app.js"&amp;gt;
            &amp;lt;environmentVariables&amp;gt;
                &amp;lt;environmentVariable name="PORT" value="%HTTP_PLATFORM_PORT%" /&amp;gt;
                &amp;lt;environmentVariable name="NODE_ENV" value="Production" /&amp;gt;
            &amp;lt;/environmentVariables&amp;gt;
        &amp;lt;/httpPlatform&amp;gt;
  &amp;lt;/system.webServer&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should check if the paths in the configuration file are correct. Once the file has been saved, that's it. If you visit the the URL configured in the bindings in IIS it will now route the traffic to the node.js webserver which will be managed by IIS.&lt;/p&gt;

&lt;p&gt;More info:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.hanselman.com/blog/AnnouncingRunningRubyOnRailsOnIIS8OrAnythingElseReallyWithTheNewHttpPlatformHandler.aspx" rel="noopener noreferrer"&gt;Scott Hanselman wrote about the extension&lt;/a&gt; and &lt;a href="https://azure.microsoft.com/en-in/resources/videos/the-http-platform-handler-with-scott-hanselman/" rel="noopener noreferrer"&gt;has a video on it&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/previous-versions/azure/windows-server-azure-pack/mt125371(v%3Dtechnet.10)" rel="noopener noreferrer"&gt;Microsoft documentation on using the module&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a cross post from my &lt;a href="https://eysermans.com/post/using-http-platform-handler-to-host-a-node-js-application-via-iis" rel="noopener noreferrer"&gt;own blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>hosting</category>
      <category>windows</category>
      <category>iis</category>
    </item>
    <item>
      <title>Connecting to a Microsoft SQL Server database on macOS using Python</title>
      <dc:creator>Peter Eysermans</dc:creator>
      <pubDate>Thu, 08 Aug 2019 10:45:09 +0000</pubDate>
      <link>https://dev.to/petereysermans/things-i-wish-i-knew-before-i-got-started-with-cosmosdb-454e</link>
      <guid>https://dev.to/petereysermans/things-i-wish-i-knew-before-i-got-started-with-cosmosdb-454e</guid>
      <description>&lt;p&gt;There are always situations where I want to automate small tasks. I like using Python for these kind of things, you can quickly get something working without much hassle. I needed to perform some database changes in a Microsoft SQL Server database and wanted to connect to it using Python. On Windows this is usually pretty straight forward. But I use macOS as my main operating system and I had some hurdles along the way so here is a quick how to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing
&lt;/h2&gt;

&lt;p&gt;I found an &lt;a href="https://www.sinafathi.com/connect-to-ms-sql-on-macos-using-python/"&gt;article with the same topic from 2017&lt;/a&gt;. If &lt;a href="https://brew.sh/index_nl"&gt;Homebrew&lt;/a&gt; isn't installed yet let's do that first. It's an excellent package manager for macOS. Paste the following command in the terminal to install it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once finished run the following commands to install the &lt;a href="https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-2017#microsoft-odbc-driver-131-for-sql-server"&gt;Microsoft ODBC Driver 13.1 for SQL Server&lt;/a&gt;. This driver will be used to connect to the MS SQL database.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release
brew update
brew install msodbcsql@13.1.9.2 mssql-tools@14.0.6.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Python package: pyodbc or pypyodbc
&lt;/h2&gt;

&lt;p&gt;With the driver installed, we'll be using a Python package that uses the driver to connect to the database. There are two frequently used packages to connect in Python: &lt;a href="https://github.com/mkleehammer/pyodbc"&gt;&lt;code&gt;pyodbc&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/jiangwen365/pypyodbc"&gt;&lt;code&gt;pypyodbc&lt;/code&gt;&lt;/a&gt;. &lt;code&gt;pypyodbc&lt;/code&gt; is a pure Python re-implementation of &lt;code&gt;pyodbc&lt;/code&gt;. The main thing I took a way was that &lt;code&gt;pypyodbc&lt;/code&gt; is easier to set up on different platforms. I could not get &lt;code&gt;pyodbc&lt;/code&gt; working, it simply wouldn't connect to the database. &lt;/p&gt;

&lt;p&gt;Installing &lt;code&gt;pypyodbc&lt;/code&gt; can be done using &lt;a href="https://pypi.org/project/pip/"&gt;pip, the python package installer&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install pypyodbc
&lt;/code&gt;&lt;/pre&gt;

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

&lt;p&gt;Now that the necessary components have been installed, let's open our favorite code editor and write code. The first thing that needs to be done is importing &lt;code&gt;pypyodbc&lt;/code&gt;. The script starts with this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import pypyodbc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then we need a connection to the database:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sqlConnection = pypyodbc.connect(
                "Driver={ODBC Driver 13 for SQL Server};"
        "Server=&amp;lt;server IP address&amp;gt;;"
        "Database=&amp;lt;database&amp;gt;;"
        "uid=&amp;lt;username&amp;gt;;pwd=&amp;lt;password&amp;gt;");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note that you have to replace four values in this code: &lt;code&gt;server IP address&lt;/code&gt;, &lt;code&gt;database&lt;/code&gt; , &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt;. The value for the driver is a hard coded value which indicates what driver to use to connect to the database, this value points to the driver that was installed earlier.&lt;/p&gt;

&lt;p&gt;Now all what rests is use the connection and run a query.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cursor = sqlConnection.cursor()
cursor.execute("select * from Values")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The cursor now contains the result of our query, the property &lt;code&gt;cursor.rowcount&lt;/code&gt; returns the number of rows the query returned. It's now possible to loop through the rows and access the different columns:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for row in cursor:
    print(cursor)
    # first column
    firstColumn = row[0]
    # ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When we're done, we need to clean up the cursor and database connection by closing it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cursor.close()
sqlConnection.close()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And that's it, save the file and use the &lt;code&gt;python &amp;lt;filename&amp;gt;.py&lt;/code&gt;  or &lt;code&gt;python3 &amp;lt;filename.py&amp;gt;&lt;/code&gt; command, this depends on your configuration, to run. Here is the entire script:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import pypyodbc

sqlConnection = pypyodbc.connect(
                "Driver={ODBC Driver 13 for SQL Server};"
        "Server=&amp;lt;server IP address&amp;gt;;"
        "Database=&amp;lt;database&amp;gt;;"
        "uid=&amp;lt;username&amp;gt;;pwd=&amp;lt;password&amp;gt;");

cursor = sqlConnection.cursor()
cursor.execute("select * from Values")

for row in cursor:
    print(cursor)
    # first column
    firstColumn = row[0]
    # ...

cursor.close()
sqlConnection.close()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;with&lt;/code&gt; syntax can also be used to automatically close the cursor and the connection, this is another way of writing the same script:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import pypyodbc

with pypyodbc.connect(
        "Driver={ODBC Driver 13 for SQL Server};"
        "Server=&amp;lt;server IP address&amp;gt;;"
        "Database=&amp;lt;database&amp;gt;;"
        "uid=&amp;lt;username&amp;gt;;pwd=&amp;lt;password&amp;gt;") as sqlConnection:

    with sqlConnection.cursor() as cursor:

        cursor.execute("select * from Values")

        for row in cursor:
            print(cursor)
            # first column
            firstColumn = row[0]
            # ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you're looking for some more reading on the topic: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/@DrGabrielA81/python-how-connect-to-and-manage-a-database-68b113a5ca62"&gt;Python HOW: Connect to, and Manage a Database&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>database</category>
      <category>microsoftsqlserver</category>
      <category>macos</category>
    </item>
    <item>
      <title>Things I wish I knew before I got started with CosmosDB</title>
      <dc:creator>Peter Eysermans</dc:creator>
      <pubDate>Wed, 31 Jul 2019 20:59:27 +0000</pubDate>
      <link>https://dev.to/petereysermans/things-i-wish-i-knew-before-i-got-started-with-cosmosdb-4o05</link>
      <guid>https://dev.to/petereysermans/things-i-wish-i-knew-before-i-got-started-with-cosmosdb-4o05</guid>
      <description>&lt;p&gt;Lately I've been working on a project using Cosmos DB on Azure. I really like the simplicity of a document DB. However there were some things I learned while on the job which I wished somebody told me before starting with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cosmos DB?
&lt;/h2&gt;

&lt;p&gt;Cosmos DB is Microsoft's flavoured document DB, you could call it Microsoft's Mongo DB that runs on Azure. On contrary to a normal SQL database, a document DB stores documents in the database. There is no schema, so you don't need to define columns and data types. Instead you pass a document to the document database and it will store it in JSON for you. This also means that you can add and remove properties on a document without having to change other documents which store similar information. An example: if there are 2 documents in the database which represent a User, the first User can have an address and it's perfectly possible for the second User to not have an address.&lt;/p&gt;

&lt;p&gt;First user:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    id: "41bb417e-c942-4df2-96f0-cd2c3e1b2f91",
    name: "User 1",
    street: "My street",
    number: 55,
    postalCode: 1234,
    city: "Antwerp"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Second user:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    id: "cc4f3a5b-5e1c-4cdf-8167-dbd363538e26",
    name: "User 2"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we got the basics, let's look into some operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parameterized query
&lt;/h2&gt;

&lt;p&gt;Let's start with the very basic. If you'd like to run a query using parameters with C#, the &lt;code&gt;SqlQuerySpec&lt;/code&gt; class can be used and passed to the &lt;code&gt;DocumentClient&lt;/code&gt;. Both classes can be found in the &lt;a href="https://www.nuget.org/packages/Microsoft.Azure.DocumentDB/"&gt;Microsoft.Azure.DocumentDB package&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var querySpec = new SqlQuerySpec {
    QueryText = "select * from c where c.id = @id",
    Parameters = new SqlParameterCollection {
        new SqlParameter { 
            Name = "@id",
            Value = userId
        }
    }
}

// These properties can be found in the Azure portal.
var documentDbUri = "cosmosdb-uri";
var databaseId = "cosmosdb-database";
var collectionId = "cosmosdb-collection";

var documentClient = new DocumentClient(new Uri(documentDbUri), documentDbKey);
var database = documentClient.CreateDatabaseQuery().FirstOrDefault(d =&amp;gt; d.Id == databaseId);
var collection = documentClient.CreateDocumentCollectionQuery().FirstOrDefault(c =&amp;gt; c.Id == collectionId);
var queryResult = documentClient.CreateQuery(collection.DocumentsLink, query);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  ARRAY_CONTAINS
&lt;/h2&gt;

&lt;p&gt;This function's name pretty much speaks for itself. If a document has a property which is an array, &lt;code&gt;ARRAY_CONTAINS&lt;/code&gt; can be used in a query to check if the array contains a certain value.&lt;/p&gt;

&lt;p&gt;An example, this is our document:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    id: "9476d2bb-6f19-483f-9a59-446ddc693050",
    name: "Jane Doe",
    roles: [
        "manager",
        "reporting"
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To query all the users that have the manager role:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select * from c where ARRAY_CONTAINS(c.roles, "manager")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the property is an array of objects, you can also pass an object to the &lt;code&gt;ARRAY_CONTAINS&lt;/code&gt; function. More info can be found in &lt;a href="https://stackoverflow.com/questions/35137136/documentdb-sql-with-array-contains"&gt;this Stackoverflow question&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT  *
FROM    food as f
WHERE   ARRAY_CONTAINS(f.servings, {"description":"bar"}, true)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Another great use of this function is using it as an alternative for the traditional SQL &lt;code&gt;in&lt;/code&gt; keyword. If you would want to check if an ID is in an array that is passed as a parameter you would write something like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT *
FROM Orders
WHERE CustomerId in (@customerIds)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;@customerIds&lt;/code&gt; would then be an array of ids which is passed from C#.&lt;/p&gt;

&lt;p&gt;To do a similar query on a CosmosDB instance, &lt;code&gt;ARRAY_CONTAINS&lt;/code&gt; can be used. The array is passed as a parameter and &lt;code&gt;ARRAY_CONTAINS&lt;/code&gt; can be used to check if the id is in the given parameter. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var customerIds = new List&amp;lt;int&amp;gt; { 5, 6, 7, 8 };

var querySpec = new SqlQuerySpec {
    QueryText = "select * from c where ARRAY_CONTAINS(@customerIds, c.customerId)",
    Parameters = new SqlParameterCollection {
        new SqlParameter { 
            Name = "@customerIds",
            Value = customerIds
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Count
&lt;/h2&gt;

&lt;p&gt;If you want to know how many records are in the result of a given query, there are two ways of getting the result. Using the LINQ &lt;code&gt;Count&lt;/code&gt; method.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// These properties can be found in the Azure portal.
var documentDbUri = "cosmosdb-uri";
var databaseId = "cosmosdb-database";
var collectionId = "cosmosdb-collection";

var documentClient = new DocumentClient(new Uri(documentDbUri), documentDbKey);
var database = documentClient.CreateDatabaseQuery().FirstOrDefault(d =&amp;gt; d.Id == databaseId);
var collection = documentClient.CreateDocumentCollectionQuery().FirstOrDefault(c =&amp;gt; c.Id == collectionId);

var count = documentClient.CreateDocumentQuery&amp;lt;User&amp;gt;(collection.DocumentsLink)
                          .Where(u =&amp;gt; u.city == "Antwerp")
                          .Count();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or you can use the &lt;code&gt;COUNT&lt;/code&gt; keyword in a SQL query, this query can be ran using a parameterized query.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT VALUE COUNT(d) FROM d where city = 'Antwerp'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/45183435/how-to-construct-iqueryable-query-using-linq-when-i-just-need-count-without-read"&gt;Read more about count in Cosmos DB&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Client
&lt;/h2&gt;

&lt;p&gt;Although the Azure portal allows to do any kind of operation on the document database, it's a very clunky way to work. I'm a big fan of using a dedicated client. Although the &lt;a href="https://azure.microsoft.com/en-us/features/storage-explorer/"&gt;Microsoft Azure Storage Explorer&lt;/a&gt; still has some rough edges, the Cosmos DB support is still in preview, it works well. And besides managing documents in a Cosmos DB on Azure you can also manage your storage account.&lt;/p&gt;

&lt;p&gt;Another option is the open source &lt;a href="https://github.com/sachabruttin/CosmosDbExplorer"&gt;Cosmos DB explorer&lt;/a&gt; but it has less options than the Storage Explorer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Like keyword
&lt;/h2&gt;

&lt;p&gt;In traditional SQL the &lt;code&gt;like&lt;/code&gt; keyword can be used to filter a string field on a certain value. CosmosDB foresees in &lt;a href="https://stackoverflow.com/questions/36663017/does-documentdb-support-the-like-keyword-in-queries"&gt;equivalents for the like keyword&lt;/a&gt;. Let's go over the different options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Show all rows where a specific column contains a certain value
&lt;/h3&gt;

&lt;p&gt;SQL:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select * from Table where Column like '%value%'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;CosmosDB:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select * from d where CONTAINS(d.Column, 'value')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Show all rows where a specific column starts with a certain value
&lt;/h3&gt;

&lt;p&gt;SQL: &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select * from Table where Column like 'value%'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;CosmosDB:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select * from d where STARTSWITH(d.Column, 'value')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Show all rows where a specific column ends with a certain value
&lt;/h3&gt;

&lt;p&gt;SQL:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select * from Table where Column like '%value'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;CosmosDB:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select * from d where ENDSWITH(d.Column, 'value')&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;As you can see if you compare CosmosDB with a relational SQL database there are some things that work quite different. I hope this gives you a head start with Cosmos DB. Feel free to ping me if you have any other tips or remarks.&lt;/p&gt;

</description>
      <category>cosmosdb</category>
      <category>documentdb</category>
      <category>sql</category>
    </item>
    <item>
      <title>Testing request permissions in an Android application</title>
      <dc:creator>Peter Eysermans</dc:creator>
      <pubDate>Mon, 15 Jul 2019 11:12:02 +0000</pubDate>
      <link>https://dev.to/petereysermans/testing-request-permissions-in-an-android-application-26em</link>
      <guid>https://dev.to/petereysermans/testing-request-permissions-in-an-android-application-26em</guid>
      <description>&lt;p&gt;Originally posted on the 15th of july 2019 on my &lt;a href="https://eysermans.com/post/testing-request-permissions-in-an-android-application" rel="noopener noreferrer"&gt;own blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While working on an Android application I wanted to test permission requests. This application needed the location permission, typically this is code that is written once and when it is marked as done never looked at again. I wanted to create some UI tests to ensure that everything works and will still work in the future as expected.&lt;/p&gt;

&lt;p&gt;Let's start this off with creating a sample application. It's written in Kotlin with API 23 as minimum API level and it also uses the androidx.* artifacts.&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%2Feysermans.com%2Fimages%2Farticles%2Ftesting-request-permissions-in-an-android-application%2FScreenshot_2019-07-13_at_22-4b0a5092-dde1-4210-a438-9b8566148325.07.27.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%2Feysermans.com%2Fimages%2Farticles%2Ftesting-request-permissions-in-an-android-application%2FScreenshot_2019-07-13_at_22-4b0a5092-dde1-4210-a438-9b8566148325.07.27.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Following permissions are added in the &lt;code&gt;AndroidManifest.xml&lt;/code&gt; file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&amp;gt;
&amp;lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When the activity is created, the app will check if the location permissions have been granted. If they haven't been granted yet, the app will request them. When the permissions are denied, the app will show &lt;code&gt;Permissions denied&lt;/code&gt; to the user. When the permissions are granted, it will show &lt;code&gt;Permissions granted&lt;/code&gt;. Pretty straightforward.&lt;/p&gt;

&lt;p&gt;This is the overridden &lt;code&gt;onCreate&lt;/code&gt; method: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) 
               != PackageManager.PERMISSION_GRANTED &amp;amp;&amp;amp; 
            ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) 
               != PackageManager.PERMISSION_GRANTED) {

            requestPermissions(
                arrayOf(
                    Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.ACCESS_COARSE_LOCATION
                ), LocationPermissionRequestCode)
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This code checks if the &lt;code&gt;ACCESS_FINE_LOCATION&lt;/code&gt; and the &lt;code&gt;ACCESS_COARSE_LOCATION&lt;/code&gt; permissions have been granted. If not they will be requested from the user. The &lt;code&gt;LocationPermissionRequestCode&lt;/code&gt; variable is a constant to identify the request. In the sample application it is set to &lt;code&gt;1&lt;/code&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%2Feysermans.com%2Fimages%2Farticles%2Ftesting-request-permissions-in-an-android-application%2FScreenshot_2019-07-13_at_22-1ea4eba7-19ea-4334-bdef-51c1fc7515df.27.16.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%2Feysermans.com%2Fimages%2Farticles%2Ftesting-request-permissions-in-an-android-application%2FScreenshot_2019-07-13_at_22-1ea4eba7-19ea-4334-bdef-51c1fc7515df.27.16.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next we need to handle the response of the user. To do this, there is a method which the activity provides that can be overridden. The &lt;code&gt;onRequestPermissionsResult&lt;/code&gt; method is overridden and a switch statement determines for which request the response is received. Note that the same &lt;code&gt;LocationPermissionRequestCode&lt;/code&gt; variable is used as above. According to the result of the request the text of the &lt;code&gt;feedbackLabel&lt;/code&gt; is changed.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;override fun onRequestPermissionsResult(requestCode: Int, permissions: Array&amp;lt;out String&amp;gt;, grantResults: IntArray) {

        when(requestCode) {
            LocationPermissionRequestCode -&amp;gt; {

                if((grantResults.isNotEmpty() &amp;amp;&amp;amp; grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                    feedbackLabel.text = "Permissions granted"
                } else {
                    feedbackLabel.text = "Permissions denied"
                }
                return
            }
            else -&amp;gt; {

            }
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note: to access the &lt;code&gt;feedbackLabel&lt;/code&gt; I'm using the &lt;a href="https://kotlinlang.org/docs/tutorials/android-plugin.html" rel="noopener noreferrer"&gt;Kotlin Android Extensions&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%2Feysermans.com%2Fimages%2Farticles%2Ftesting-request-permissions-in-an-android-application%2FScreenshot_2019-07-13_at_22-61b9fafd-eaf0-4b38-96d6-6f53fd13e768.33.49.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%2Feysermans.com%2Fimages%2Farticles%2Ftesting-request-permissions-in-an-android-application%2FScreenshot_2019-07-13_at_22-61b9fafd-eaf0-4b38-96d6-6f53fd13e768.33.49.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the sample app is working let's get to the testing part. Code like this is often written once, tested once and then never touched again. A developer will grant the permissions and go on with his life. If a bug creeps in it will be noticed too late or not at all. So let's write some UI tests to verify that the app behaves as expected. &lt;a href="https://medium.com/@smalam119/introduction-to-android-ui-testing-f05a251ab08d" rel="noopener noreferrer"&gt;UI testing on Android is often done using Espresso&lt;/a&gt; and it works quite well. There even is an &lt;a href="https://www.thedroidsonroids.com/blog/android/espresso-test-recording" rel="noopener noreferrer"&gt;Espresso test recorder built into Android Studio&lt;/a&gt; to quickly record tests.&lt;/p&gt;

&lt;p&gt;Let's record our first Espresso test, if the user denies the permission the &lt;code&gt;feedbackLabel&lt;/code&gt; should read &lt;code&gt;Permissions denied&lt;/code&gt;. In Android Studio select &lt;code&gt;Run &amp;gt; Record Espresso Test&lt;/code&gt; from the menu. &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%2Feysermans.com%2Fimages%2Farticles%2Ftesting-request-permissions-in-an-android-application%2FScreenshot_2019-07-13_at_22-5f7cc541-7df5-4c98-b2dd-85bcf9466246.39.27.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%2Feysermans.com%2Fimages%2Farticles%2Ftesting-request-permissions-in-an-android-application%2FScreenshot_2019-07-13_at_22-5f7cc541-7df5-4c98-b2dd-85bcf9466246.39.27.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The test recorder will open and a log of all actions that have happened on the device will appear. After clicking the &lt;code&gt;Deny&lt;/code&gt; button assert that the &lt;code&gt;feedbackLabel&lt;/code&gt; has the expected value.&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%2Feysermans.com%2Fimages%2Farticles%2Ftesting-request-permissions-in-an-android-application%2FScreenshot_2019-07-13_at_22-e00c1d8f-81fb-4353-9767-8f75414be00b.40.35.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%2Feysermans.com%2Fimages%2Farticles%2Ftesting-request-permissions-in-an-android-application%2FScreenshot_2019-07-13_at_22-e00c1d8f-81fb-4353-9767-8f75414be00b.40.35.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If Espresso has not been added to the gradle file of the application, Android Studio will propose to do it for you.&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%2Feysermans.com%2Fimages%2Farticles%2Ftesting-request-permissions-in-an-android-application%2FScreenshot_2019-07-13_at_22-932c51ce-c5aa-4a87-ad3f-77235c3f9d3c.40.50.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%2Feysermans.com%2Fimages%2Farticles%2Ftesting-request-permissions-in-an-android-application%2FScreenshot_2019-07-13_at_22-932c51ce-c5aa-4a87-ad3f-77235c3f9d3c.40.50.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately Espresso can't be used for this kind of test. &lt;a href="https://stackoverflow.com/a/50383212/145585" rel="noopener noreferrer"&gt;Espresso only works on the current package&lt;/a&gt; and the &lt;code&gt;Allow&lt;/code&gt; and &lt;code&gt;Deny&lt;/code&gt; buttons from the Permissions dialog are from another package. As you can see in the test record, the click on the &lt;code&gt;Deny&lt;/code&gt; button is not recorded to the list of actions.&lt;/p&gt;

&lt;p&gt;There is however a solution, next to Espresso there is also the &lt;a href="https://developer.android.com/training/testing/ui-automator" rel="noopener noreferrer"&gt;UI Automator testing framework&lt;/a&gt;. This framework has no problem with accessing elements from another package. We can't use the test recorder so the test will have to be coded but this is pretty straightforward. This line in the gradle file will add UI Automator:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.3'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And the test becomes:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RunWith(AndroidJUnit4::class)
class MainActivityTests {

    private var device : UiDevice? = null

    @get:Rule
    var mainActivityTestRule = ActivityTestRule(MainActivity::class.java)

    @Before
    fun setUp() {
        this.device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
    }

    @Test
    fun testFeedbackLocationPermissionDenied() {
        val denyButton = this.device?.findObject(UiSelector().text("DENY"))
        val permissionDeniedMessage = this.device?.findObject(UiSelector().text("Permission denied"))

        denyButton!!.click()

        assert(permissionDeniedMessage!!.exists())
    }

    @Test
    fun testFeedbackLocationPermissionAllowed() {
        val allowButton = this.device?.findObject(UiSelector().text("ALLOW"))
        var permissionAllowedMessage = this.device?.findObject(UiSelector().text("Permission allowed"))
        allowButton!!.click()
        assert(permissionAllowedMessage!!.exists())
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;testFeedbackLocationPermissionAllowed&lt;/code&gt; test will check the message when the permission is allowed, the &lt;code&gt;testFeedbackLocationPermissionDenied&lt;/code&gt; will check the message when the permission is denied. &lt;/p&gt;

&lt;p&gt;There is however a problem with these tests. Once the permission has been allowed, the tests will fail when they are run again. If you think about it, it's not surprising. Because the permission is already granted, the permission popup will no longer be shown the second, third, fourth, ... time the tests are run.&lt;/p&gt;

&lt;p&gt;To fix this the granted permissions need to be cleared every time the tests are run. &lt;a href="https://stackoverflow.com/questions/43462172/android-revoke-permission-at-start-of-each-test" rel="noopener noreferrer"&gt;Clearing the permission can be done using &lt;code&gt;pm revoke&lt;/code&gt;.&lt;/a&gt; These commands are added to the &lt;code&gt;After&lt;/code&gt; method to clean up the permissions.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@After
fun tearDown() {
   InstrumentationRegistry.getInstrumentation().uiAutomation.
       executeShellCommand("pm revoke ${InstrumentationRegistry.getInstrumentation().targetContext.packageName} android.permission.ACCESS_COARSE_LOCATION")

   InstrumentationRegistry.getInstrumentation().uiAutomation.
       executeShellCommand("pm revoke ${InstrumentationRegistry.getInstrumentation().targetContext.packageName} android.permission.ACCESS_FINE_LOCATION")
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When the &lt;code&gt;tearDown&lt;/code&gt; executes logcat logs the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2019-07-15 11:09:43.639 21138-21154/com.eysermans.permissionuitesting W/UiAutomation: UiAutomation.revokeRuntimePermission() is more robust and should be used instead of 'pm revoke'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So instead of using &lt;code&gt;pm revoke&lt;/code&gt; we should use &lt;a href="https://developer.android.com/reference/kotlin/android/app/UiAutomation#revokeRuntimePermission%28kotlin.String,%20kotlin.String%29" rel="noopener noreferrer"&gt;&lt;code&gt;revokeRuntimePermission&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@After
fun tearDown() {
    InstrumentationRegistry.getInstrumentation().uiAutomation.revokeRuntimePermission(
        InstrumentationRegistry.getInstrumentation().targetContext.packageName,
        Manifest.permission.ACCESS_COARSE_LOCATION)

    InstrumentationRegistry.getInstrumentation().uiAutomation.revokeRuntimePermission(
        InstrumentationRegistry.getInstrumentation().targetContext.packageName,
        Manifest.permission.ACCESS_FINE_LOCATION)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Unfortunately this didn't work either. Every time the &lt;code&gt;testFeedbackLocationPermissionAllowed&lt;/code&gt; test ran it failed stating that more information can be found in logcat. However I did not find any additional error logging in logcat. It just did not work.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Test failed to run to completion. Reason: 'Instrumentation run failed due to 'Process crashed.''. Check device logcat for details
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's explore another option, using the &lt;a href="https://developer.android.com/training/testing/junit-runner#using-android-test-orchestrator" rel="noopener noreferrer"&gt;Android Test Orchestrator&lt;/a&gt;. Add the dependency to the gradle file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;androidTestUtil 'androidx.test:orchestrator:1.2.0'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then add the following line to the &lt;code&gt;defaultConfig&lt;/code&gt; section of the gradle file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;testInstrumentationRunnerArguments clearPackageData: 'true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And add the &lt;code&gt;testOptions&lt;/code&gt; section to the &lt;code&gt;android&lt;/code&gt; section:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;testOptions {
    execution 'ANDROIDX_TEST_ORCHESTRATOR'

    unitTests {
        includeAndroidResources = true
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The gradle file now looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.eysermans.permissionuitesting"
        minSdkVersion 23
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        testInstrumentationRunnerArguments clearPackageData: 'true'
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    testOptions {
        execution 'ANDROIDX_TEST_ORCHESTRATOR'

        unitTests {
            includeAndroidResources = true
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.core:core-ktx:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.2.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    androidTestImplementation 'androidx.test:rules:1.3.0-alpha01'
    androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.3'

    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestUtil 'androidx.test:orchestrator:1.2.0'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;tearDown&lt;/code&gt; method can now completely be removed and the &lt;code&gt;testFeedbackLocationPermissionAllowed&lt;/code&gt; method can now be run over and over again. &lt;/p&gt;

&lt;p&gt;It took some work but this solution works. The permissions are cleared before every test. I preferred using a &lt;code&gt;tearDown&lt;/code&gt; method because it is more straightforward. But unfortunately it did not work as expected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/petereysermans/android-permission-ui-testing" rel="noopener noreferrer"&gt;The sample application is available on GitHub.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More links on the subject:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.egorand.me/testing-runtime-permissions-lessons-learned/" rel="noopener noreferrer"&gt;Testing Runtime Permissions: Lessons Learned&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/43462172/android-revoke-permission-at-start-of-each-test" rel="noopener noreferrer"&gt;Android revoke permission at start of each test&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/stepstone-tech/android-test-orchestrator-unmasked-83b8879928fa" rel="noopener noreferrer"&gt;Android Test Orchestrator unmasked&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/training/testing/junit-runner#ato-gradle" rel="noopener noreferrer"&gt;Enable the Android Test Orchestrator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>android</category>
      <category>testing</category>
      <category>development</category>
      <category>uitesting</category>
    </item>
    <item>
      <title>Using the Digispark as a cheap USB Rubber Ducky</title>
      <dc:creator>Peter Eysermans</dc:creator>
      <pubDate>Fri, 05 Apr 2019 20:40:44 +0000</pubDate>
      <link>https://dev.to/petereysermans/using-the-digispark-as-a-cheap-usb-rubber-ducky-29cf</link>
      <guid>https://dev.to/petereysermans/using-the-digispark-as-a-cheap-usb-rubber-ducky-29cf</guid>
      <description>&lt;p&gt;&lt;strong&gt;Disclaimer: This post is for fun, learning and experimenting. Use these tools wisely, in no way am I encouraging malicious use of them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Originally posted on the 5th of april 2019 on my &lt;a href="https://eysermans.com/post/using-the-digispark-as-a-cheap-usb-rubber-ducky" rel="noopener noreferrer"&gt;own blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Last week I came across an interesting device, the &lt;a href="https://shop.hak5.org/products/usb-rubber-ducky-deluxe" rel="noopener noreferrer"&gt;USB Rubber Ducky&lt;/a&gt;. It looks like a normal USB stick but when you plug it into a computer, it emulates  a keyboard. You can load a script onto the Rubber Ducky and it will execute them as keystrokes on the computer where the stick is plugged in. Because it executes more than 1000 words per minute, the possibilities are  endless from running pentest task to malicious things like installing a backdoor.&lt;/p&gt;

&lt;p&gt;I wanted to play around with it but unfortunately shipping the stick to Europe/Belgium costs almost as much as the stick. Luckily there is a &lt;a href="https://hackernoon.com/low-cost-usb-rubber-ducky-pen-test-tool-for-3-using-digispark-and-duck2spark-5d59afc1910" rel="noopener noreferrer"&gt;post on Hackernoon on how to make your own USB Rubber Ducky with a Digispark&lt;/a&gt;. The &lt;a href="http://digistump.com/products/1" rel="noopener noreferrer"&gt;Digispark&lt;/a&gt; is similar to the Arduino but it's cheaper, smaller and less powerful. The end result actually looks better because it is much smaller than the Rubber Ducky. One drawback, the Digispark does not have a micro SD slot so there is no disk space to use.&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%2Feysermans.com%2Fimages%2Farticles%2Fusing-the-digispark-as-a-cheap-usb-rubber-ducky%2Fdigispark-up-close.jpg" 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%2Feysermans.com%2Fimages%2Farticles%2Fusing-the-digispark-as-a-cheap-usb-rubber-ducky%2Fdigispark-up-close.jpg" alt="Digispark up close"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is it next to a pen. I'm still amazed how small it is.&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%2Feysermans.com%2Fimages%2Farticles%2Fusing-the-digispark-as-a-cheap-usb-rubber-ducky%2Fdigispark-vs-pen.jpg" 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%2Feysermans.com%2Fimages%2Farticles%2Fusing-the-digispark-as-a-cheap-usb-rubber-ducky%2Fdigispark-vs-pen.jpg" alt="Digispark VS pen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Buying these low budget components can be challenging. I have the impression that they are much easier and cheaper to get in the States. In some cases there are alternatives on &lt;a href="https://www.amazon.de/" rel="noopener noreferrer"&gt;Amazon Germany&lt;/a&gt;. But the Digispark was too cheap and shipping costs were too high. Eventually I found them on a &lt;a href="https://www.conrad.be/p/joy-it-arduino-uitbreidingsprintplaat-digispark-microcontroller-1503743" rel="noopener noreferrer"&gt;local webshop&lt;/a&gt; for 6,49 €. I needed some other things so I could reduce the shipping costs.&lt;/p&gt;

&lt;p&gt;To get started there are a lot of resources on the internet. But most of the scripts and blog posts are targeted for Windows. However I found an excellent blog post with a hello world example on &lt;a href="https://pennsylforniageek.tumblr.com/post/169014885841/how-to-setup-and-run-the-digispark-attiny85-as" rel="noopener noreferrer"&gt;how to set up the Digispark as a Rubber Ducky on Mac OS X&lt;/a&gt;. This is the hello world script that will be used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include "DigiKeyboard.h"

boolean didRun = false;

void setup() {}

void loop() {
  while (didRun == false) {
    DigiKeyboard.sendKeyStroke(KEY_SPACE, MOD_GUI_LEFT);
    DigiKeyboard.delay(500);
    DigiKeyboard.println("terminal");
    DigiKeyboard.delay(500);
    DigiKeyboard.println("say Hello World");
    didRun = true;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script uses the default shortcut to activate Spotlight, types &lt;code&gt;terminal&lt;/code&gt; and hits enter. This should open the terminal, after waiting half a second it types and executes the command &lt;code&gt;say Hello World&lt;/code&gt;. When I tried uploading this script via the Arduino IDE, it could never find my Digispark. &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%2Feysermans.com%2Fimages%2Farticles%2Fusing-the-digispark-as-a-cheap-usb-rubber-ducky%2Fapple-adapter.jpg" 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%2Feysermans.com%2Fimages%2Farticles%2Fusing-the-digispark-as-a-cheap-usb-rubber-ducky%2Fapple-adapter.jpg" alt="Apple USB tp USB-C adapter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was using an Apple USB to USB-C adapter to connect the Digispark to my Macbook pro. After some googling I discovered that the middle pins in the USB connector of the Digispark are quite short and that in some cases it won't connect properly. After digging up a USB extension cable the Digispark connected and the script uploaded.&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%2Feysermans.com%2Fimages%2Farticles%2Fusing-the-digispark-as-a-cheap-usb-rubber-ducky%2Fusb-cable.jpg" 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%2Feysermans.com%2Fimages%2Farticles%2Fusing-the-digispark-as-a-cheap-usb-rubber-ducky%2Fusb-cable.jpg" alt="USB extension cable"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So if the device is now inserted in a target machine, the script will run. While testing the hello world script I realized there is quite a lot that can go wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What if the Spotlight key shortcut has been changed?&lt;/li&gt;
&lt;li&gt;On my laptop, when typing &lt;code&gt;terminal&lt;/code&gt; in Spotlight another file was the top result. As a result, the script did absolutely nothing.&lt;/li&gt;
&lt;li&gt;When testing the script in computer with an azerty keyboard layout, the characters were typed with a qwerty keyboard layout.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But in the end, it did work. The script ran within seconds from a device similar in size as a coin. Pretty cool. While doing some research, I found quite a lot of other resources and example scripts. Making a laptop saying Hello World is just the tip of the iceberg. Some more resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/topics/digispark-scripts" rel="noopener noreferrer"&gt;A collection of all kinds of Digispark scripts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://shop.hak5.org/products/bash-bunny" rel="noopener noreferrer"&gt;Bash Bunny, similar product to the USB Rubber Ducky&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mame82/duck2spark/" rel="noopener noreferrer"&gt;duck2spark, converting Rubber Ducky payloads to Digispark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cedarctic.github.io/digiQuack/" rel="noopener noreferrer"&gt;digiQuack, another DuckyScript to Digispark payload converter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>digispark</category>
      <category>arduino</category>
      <category>pentest</category>
      <category>experiment</category>
    </item>
    <item>
      <title>Hosting a Node.js application on Windows with IIS as reverse proxy</title>
      <dc:creator>Peter Eysermans</dc:creator>
      <pubDate>Wed, 27 Mar 2019 08:07:59 +0000</pubDate>
      <link>https://dev.to/petereysermans/hosting-a-node-js-application-on-windows-with-iis-as-reverse-proxy-397b</link>
      <guid>https://dev.to/petereysermans/hosting-a-node-js-application-on-windows-with-iis-as-reverse-proxy-397b</guid>
      <description>&lt;p&gt;Unfortunately a lot of companies are still stuck with Windows servers. Nobody ever got fired for choosing Microsoft, right. As a developer this can be frustrating  because choosing a server technology is usually limited to ASP.Net. I have experimented with hosting Node.js applications on a Windows server by using &lt;a href="https://github.com/Azure/iisnode" rel="noopener noreferrer"&gt;iisnode&lt;/a&gt;. But it is a pain to get up and running, setting the correct permissions is a time consuming chore. Microsoft has taken control of the development of the project but I get the feeling it's not very active any more. There are several Stackoverflow questions where people just give up configuring it.&lt;/p&gt;

&lt;p&gt;So I wanted to go another route. What if we could use the Node.js web server and use IIS as a reverse proxy to route traffic to the Node.js web server? We could ditch iisnode and hopefully have a more reliable solution for hosting Node.js web applications.&lt;/p&gt;

&lt;p&gt;First we need a small test project, this &lt;a href="https://medium.com/@adnanrahic/hello-world-app-with-node-js-and-express-c1eb7cfa8a30" rel="noopener noreferrer"&gt;hello world Node.js Express application&lt;/a&gt; will do:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello World!');
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To be able to run this, you need to install Node.js on your server. Once it's installed, you can run the test application by opening a command prompt and typing &lt;code&gt;node app.js&lt;/code&gt;. If everything goes well you should now be able to access the test application via &lt;code&gt;http://localhost:3000&lt;/code&gt; on your local server. &lt;/p&gt;

&lt;p&gt;To &lt;a href="https://tecadmin.net/set-up-reverse-proxy-using-iis/" rel="noopener noreferrer"&gt;configure IIS as reverse proxy&lt;/a&gt; you need to install the &lt;a href="https://www.iis.net/downloads/microsoft/url-rewrite" rel="noopener noreferrer"&gt;URL Rewrite extension&lt;/a&gt; and the &lt;a href="https://www.iis.net/downloads/microsoft/application-request-routing" rel="noopener noreferrer"&gt;Application Request Routing extension&lt;/a&gt;. The URL Rewrite extension allows you to define rules to enable URLs that are easier for users to remember and for search engines to find. The Application Request Routing extension enables scalibility features: load balancing, rule-based routing and more.&lt;/p&gt;

&lt;p&gt;Once these extensions are installed, you can begin configuring IIS. Open the Internet Information Services (IIS) Manager by opening the run window and typing the &lt;code&gt;inetmgr&lt;/code&gt; command. Select the site for which you want to set up the reverse proxy and open the URL Rewrite extension.&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%2Feysermans.com%2Fimages%2Farticles%2Fhosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy%2Furl_rewriting_extension.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%2Feysermans.com%2Fimages%2Farticles%2Fhosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy%2Furl_rewriting_extension.png" alt="Open URL Rewrite extension"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a new rule and select the &lt;code&gt;Reverse Proxy&lt;/code&gt; template. &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%2Feysermans.com%2Fimages%2Farticles%2Fhosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy%2Fadd_rule.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%2Feysermans.com%2Fimages%2Farticles%2Fhosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy%2Fadd_rule.png" alt="Add rule"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enable proxy functionality when you are prompted for it.&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%2Feysermans.com%2Fimages%2Farticles%2Fhosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy%2Fenable_proxy_functionality.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%2Feysermans.com%2Fimages%2Farticles%2Fhosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy%2Fenable_proxy_functionality.png" alt="Enable proxy functionality"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add the address of your node.js website, don't forget to include the port, to the reverse proxy rules. &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%2Feysermans.com%2Fimages%2Farticles%2Fhosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy%2Fadd_reverse_proxy_rules.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%2Feysermans.com%2Fimages%2Farticles%2Fhosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy%2Fadd_reverse_proxy_rules.png" alt="Add reverse proxy rules"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the rule has been added, the reverse proxy configuration works.&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%2Feysermans.com%2Fimages%2Farticles%2Fhosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy%2Fworking_reverse_proxy.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%2Feysermans.com%2Fimages%2Farticles%2Fhosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy%2Fworking_reverse_proxy.png" alt="Working reverse proxy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last piece that's needed is a reliable way of running the Node.js application. Starting it via the command prompt and keeping the window open is not a durable solution. If someone logs on to the server and closes the window, the website goes down. &lt;a href="http://pm2.keymetrics.io/" rel="noopener noreferrer"&gt;pm2&lt;/a&gt; is a Node.js process manager, it can be used to keep applications running. Installing pm2 is easy with npm:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm install -g pm2


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once installed, we can use these commands to manage our processes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pm2 start app.js&lt;/code&gt;: start our Node.js application&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pm2 stop&lt;/code&gt;: stop a running process&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pm2 restart&lt;/code&gt;: restart a running process&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pm2 list&lt;/code&gt;: list all running processes &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;pm2 can do so much more, check out &lt;a href="http://pm2.keymetrics.io/" rel="noopener noreferrer"&gt;their website&lt;/a&gt; for more info. My own blog is currently running on this setup.&lt;/p&gt;

&lt;p&gt;This is a cross post from my &lt;a href="https://eysermans.com/post/hosting-a-nodejs-application-on-windows-with-iis-as-reverse-proxy" rel="noopener noreferrer"&gt;own blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>hosting</category>
      <category>windows</category>
      <category>iis</category>
    </item>
  </channel>
</rss>
