<?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>Forem: Danielle Emma Vass</title>
    <description>The latest articles on Forem by Danielle Emma Vass (@daniellevass).</description>
    <link>https://forem.com/daniellevass</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%2F284036%2Fe6a01ab0-c634-4308-a4ec-16db714ba4fb.jpeg</url>
      <title>Forem: Danielle Emma Vass</title>
      <link>https://forem.com/daniellevass</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/daniellevass"/>
    <language>en</language>
    <item>
      <title>How to analyse all your Android Gradle build times from your computer</title>
      <dc:creator>Danielle Emma Vass</dc:creator>
      <pubDate>Mon, 28 Feb 2022 21:09:14 +0000</pubDate>
      <link>https://forem.com/daniellevass/how-to-analyse-all-your-android-gradle-build-times-from-your-computer-5cd0</link>
      <guid>https://forem.com/daniellevass/how-to-analyse-all-your-android-gradle-build-times-from-your-computer-5cd0</guid>
      <description>&lt;p&gt;Did you know every time you build your Android project with Gradle that data gets logged somewhere?&lt;/p&gt;

&lt;p&gt;It can be useful to understand how much time you're spending waiting around for things to build. It can help give the impact to get better equipment, or spend time working on improving it. I believe things that get tracked get improved! It can also help your performance review to evidence how much time you've saved everyone!&lt;/p&gt;

&lt;p&gt;So where do we start?&lt;/p&gt;

&lt;p&gt;These instructions are for OS X: If you open Finder or Terminal, and navigate to the &lt;code&gt;//Users/{your name}/.gradle/daemon/&lt;/code&gt; folder you will see a folder for every version of gradle you have used on your computer.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffd52zabp6jowyinvaq8j.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffd52zabp6jowyinvaq8j.png" alt="Finder window showing where the out.log files are located inside the gradle daemon directory"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside those folders are a bunch of log files that contain every build you've ever run! You can open these folders with a text editor and search for the phrase "BUILD SUCCESSFUL" or "BUILD FAILED".&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wmek3gl7fjrj7vda8n3.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wmek3gl7fjrj7vda8n3.png" alt="Screenshot of a gradle log file demonstrating a successful build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can spend some time manually looking around these files, however as programmers we can probably write something to do this for us!&lt;/p&gt;

&lt;p&gt;I've used JavaScript and NodeJs to write my tool - which your welcome to use: &lt;a href="https://gist.github.com/daniellevass/c5a7655c83bac1293d6fa3f797a0dd20" rel="noopener noreferrer"&gt;https://gist.github.com/daniellevass/c5a7655c83bac1293d6fa3f797a0dd20&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please update the directory variable on L4 to match where your files are. Also note on L6 &amp;amp; L7 this is where the output file name.&lt;/p&gt;

&lt;p&gt;I'll explain how this tool works:&lt;/p&gt;

&lt;p&gt;It first opens the directory you provide on L4. Finding the list of versions you've got records. Then parsing each file that ends in &lt;code&gt;.out.log&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The difficult part is processing each log file. First we have to find all the lines we care about - in my example this is &lt;code&gt;BUILD SUCCESSFUL&lt;/code&gt; and &lt;code&gt;BUILD FAILED&lt;/code&gt;. Once we've found a line that we care about, we have to work out the duration in a sensible format. We get lines that look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUILD SUCCESSFUL in 1m 32s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want to turn that into 92, to track the seconds uniformly. So we've had to write some processing to turn &lt;code&gt;21s&lt;/code&gt; into 21, &lt;code&gt;1m 32&lt;/code&gt; into 92, and &lt;code&gt;120ms&lt;/code&gt; into 1 (milliseconds are too much precision for me, so we're just rounding up to 1s).&lt;/p&gt;

&lt;p&gt;Once we've parsed all of those we're starting to get somewhere! The next problem is it would be useful to have the date and timestamp to indicate when these logs happened. &lt;/p&gt;

&lt;p&gt;This is a bit more challenging as each &lt;code&gt;BUILD SUCCESSFUL&lt;/code&gt; or &lt;code&gt;BUILD FAILED&lt;/code&gt; doesn't actually have a date or timestamp on that row! Fortunately almost all the other rows actually start with a timestamp!&lt;/p&gt;

&lt;p&gt;So what we're doing is checking if a row starts with &lt;code&gt;"202"&lt;/code&gt;, I've not had my laptop longer than 2020 so this matches all the timestamp rows. I then keep a local variable that holds the last timestamp read. This is good enough for my use case 🤷‍♀️. &lt;/p&gt;

&lt;p&gt;Finally once we've processed all the data we can save it to a csv file!&lt;/p&gt;

&lt;p&gt;You can use something like Microsoft Excel to open csv files, or Google Sheets. You'll need to add some headings to indicate what the data is. After you've done that, you can create a pivot table with the data.&lt;/p&gt;

&lt;p&gt;I configured the rows to be the date - in ascending order. Set up 3 values: one for AVERAGE of seconds, one for MAX of seconds, and one for COUNT of seconds. Then I set filter to status. This lets you remove out failed builds if you're not interested in that data. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fombjzy3yj0vc82ohb5oi.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fombjzy3yj0vc82ohb5oi.png" alt="Google Sheets demonstrating the pivot table of my build data"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>gradle</category>
    </item>
    <item>
      <title>Some surprising things about the order in which Spek runs things</title>
      <dc:creator>Danielle Emma Vass</dc:creator>
      <pubDate>Mon, 17 Feb 2020 20:34:29 +0000</pubDate>
      <link>https://forem.com/daniellevass/some-surprising-things-about-the-order-in-which-spek-runs-things-4l1k</link>
      <guid>https://forem.com/daniellevass/some-surprising-things-about-the-order-in-which-spek-runs-things-4l1k</guid>
      <description>&lt;p&gt;These are some of the surprising things I learned about in what order Spek (the Android testing framework) runs things, especially the &lt;code&gt;describe&lt;/code&gt;, &lt;code&gt;it&lt;/code&gt;, &lt;code&gt;afterGroup&lt;/code&gt;, &lt;code&gt;afterEachGroup&lt;/code&gt;, and &lt;code&gt;afterEachTest&lt;/code&gt;. This blog was originally posted on &lt;a href="http://www.daniellevass.com/blog/2020/01/30/spek-2/"&gt;daniellevass.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We are using &lt;a href="https://www.spekframework.org/"&gt;Spek&lt;/a&gt; at work for our testing framework for our Android library. I spent too long today trying to work out why my newly written tests were failing and I learned the order that Spek runs my instructions were not what I expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example App
&lt;/h2&gt;

&lt;p&gt;I have created a &lt;a href="https://github.com/daniellevass/spek-example"&gt;example app&lt;/a&gt; which simplifies what I was trying to do in the office.&lt;/p&gt;

&lt;p&gt;The app has a singleton for a current account - &lt;a href="https://github.com/daniellevass/spek-example/blob/master/ExampleSpek/app/src/main/java/com/danielle/examplespek/CurrentAccountImplementation.kt"&gt;CurrentAccountImplementation&lt;/a&gt;. You need to call &lt;code&gt;connect&lt;/code&gt; to get the current balance (always 0) and &lt;code&gt;disconnect&lt;/code&gt;. You then have two actions to add money and take money. You can't send any actions if you aren't connected.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Description Block
&lt;/h2&gt;

&lt;p&gt;I have created a Spek test file &lt;a href="https://github.com/daniellevass/spek-example/blob/master/ExampleSpek/app/src/test/java/com/danielle/examplespek/CurrentAccountTests.kt"&gt;CurrentAccountTests&lt;/a&gt;. My intention was to use the &lt;code&gt;describe&lt;/code&gt; and &lt;code&gt;it&lt;/code&gt; together, so that a &lt;code&gt;describe&lt;/code&gt; block would group a bunch of the instructions I wanted to flow through e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;describe("end to end flow of typical user") {
     CurrentAccountImplementation.connect()

     it("balance starts at 0") {
         assertThat(CurrentAccountImplementation.getCurrentBalance()).isEqualTo(0)
     }

     it("balance is 10 when I add 10") {
         CurrentAccountImplementation.addMoney(10)
         assertThat(CurrentAccountImplementation.getCurrentBalance()).isEqualTo(10)
     }

     it("balance is 5 when I withdraw 5") {
         CurrentAccountImplementation.takeMoney(5)
         assertThat(CurrentAccountImplementation.getCurrentBalance()).isEqualTo(5)
     }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good testing etiquette means I should ensure that I set up and tear down each test, so for this example I started with adding &lt;code&gt;afterEachGroup&lt;/code&gt; and ensuring I called &lt;code&gt;CurrentAccountImplementation.disconnect()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Second Description Block
&lt;/h2&gt;

&lt;p&gt;This worked fine until I added another &lt;code&gt;describe&lt;/code&gt; block with some more &lt;code&gt;it&lt;/code&gt; tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;describe("error handling for insufficient funds") {
    CurrentAccountImplementation.connect()

    it("balance starts at 0") {
        assertThat(CurrentAccountImplementation.getCurrentBalance()).isEqualTo(0)
    }

    it("should throw an error with insufficient funds") {
        val exception = assertThrows&amp;lt;Exception&amp;gt;("Should throw an Exception") {
            CurrentAccountImplementation.takeMoney(100)
        }

        assertThat(exception).hasMessageThat().isEqualTo("insufficient funds")
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was surprised to find that my CurrentAccount had been disconnected before the second &lt;code&gt;description&lt;/code&gt; blocks &lt;code&gt;it&lt;/code&gt; functions started running. What happened?&lt;/p&gt;

&lt;h2&gt;
  
  
  Order Spek Methods Were Called
&lt;/h2&gt;

&lt;p&gt;I ended up adding a bunch of logs to see in which order each methods were being called:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;entering describe typical user&lt;/li&gt;
&lt;li&gt;entering describe error handling insufficient funds&lt;/li&gt;
&lt;li&gt;entering it balance 0&lt;/li&gt;
&lt;li&gt;entering it balance is 10&lt;/li&gt;
&lt;li&gt;entering it balance is 5&lt;/li&gt;
&lt;li&gt;AFTER EACH GROUP ~~ resetting current account&lt;/li&gt;
&lt;li&gt;entering it balance 0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My assumption that a &lt;code&gt;description&lt;/code&gt; block would be called, then it's inner &lt;code&gt;its&lt;/code&gt; was incorrect. However, the &lt;code&gt;afterEachGroup&lt;/code&gt; was called when it finished all the &lt;code&gt;its&lt;/code&gt; in a &lt;code&gt;description&lt;/code&gt; block.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I've since learned that it's not sensible to keep state in a &lt;code&gt;description&lt;/code&gt; block, each &lt;code&gt;it&lt;/code&gt; test should be responsible for it's full lifecycle. You can use the &lt;code&gt;assertThat&lt;/code&gt; to explain what you're doing without needing the &lt;code&gt;it&lt;/code&gt; description to give more context.&lt;/p&gt;

&lt;p&gt;However the behaviour of all the &lt;code&gt;description&lt;/code&gt; blocks being called before any of the &lt;code&gt;its&lt;/code&gt; and in relation to the &lt;code&gt;afterEachGroup&lt;/code&gt; was unexpected to me and so maybe is useful to others.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary (for future Danielle):
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;all &lt;code&gt;description&lt;/code&gt; blocks are called first, then each &lt;code&gt;it&lt;/code&gt; function in order&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;afterGroup&lt;/code&gt; will call after all the &lt;code&gt;its&lt;/code&gt; in the entire file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;afterEachGroup&lt;/code&gt; will call after all the &lt;code&gt;it&lt;/code&gt; functions in a given &lt;code&gt;description&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;afterEachTest&lt;/code&gt; will call after each &lt;code&gt;it&lt;/code&gt; has completed&lt;/li&gt;
&lt;li&gt;don't keep state in the &lt;code&gt;description&lt;/code&gt; block, each &lt;code&gt;it&lt;/code&gt; should be responsible for it's own state.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How I connected our Christmas Tree Angel to Pusher</title>
      <dc:creator>Danielle Emma Vass</dc:creator>
      <pubDate>Mon, 09 Dec 2019 14:02:00 +0000</pubDate>
      <link>https://forem.com/daniellevass/how-i-connected-our-christmas-tree-angel-to-pusher-40jn</link>
      <guid>https://forem.com/daniellevass/how-i-connected-our-christmas-tree-angel-to-pusher-40jn</guid>
      <description>&lt;p&gt;This is my first post on dev.to - I feel like considering my name is &lt;a href="https://twitter.com/de_velopment"&gt;Danielle Emma Vass&lt;/a&gt; I belong here (and would appreciate more DEV stickers to label all my things with please 😊) &lt;/p&gt;

&lt;p&gt;Currently, I am a mobile SDK engineer at Pusher and in this post I will explain how I bought some Christmas cheer to our office with an internet connected angel!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/YnHXKHri3xV1ROU9RD/giphy-downsized-large.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/YnHXKHri3xV1ROU9RD/giphy-downsized-large.gif" alt="image of the angel in action" width="270" height="480"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://i.giphy.com/media/H28aRvX9sdSJr68YDO/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/H28aRvX9sdSJr68YDO/giphy.gif" alt="image of her on the christmas tree" width="270" height="480"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Firstly, why?!
&lt;/h2&gt;

&lt;p&gt;Early November, our office manager at Pusher asked asked if I could crochet an angel for the office. She knew I was a &lt;a href="https://www.instagram.com/daniellevass_1/"&gt;keen crocheter&lt;/a&gt; and I figured this could be a fun project where I'd have to make up my own pattern!&lt;/p&gt;

&lt;p&gt;Later in the month I was talking to my Mum about my grand angel plans. She thought about it for a minute and asked if I could make it like my friend Jo's wedding dress, and connect the angel to the Internet. For background, my friend's dress was connected to Twitter, and you could &lt;a href="https://medium.com/samsung-internet-dev/tweet-my-wedding-dress-e08fb90b097f"&gt;tweet at her dress&lt;/a&gt; and it would change colour to whatever you tweeted at it!&lt;/p&gt;

&lt;p&gt;I figured instead of connecting it to Twitter, I could use one of our own products &lt;a href="https://pusher.com/channels"&gt;Channels&lt;/a&gt; - this would enable people to change the colour in almost real time!&lt;/p&gt;

&lt;p&gt;This was beginning to look like an ambitious project. So I began by splitting the work up into the separate, manageable areas; I needed to crochet the angel, build some electronics, write some microcontroller code, and construct a web app.&lt;/p&gt;
&lt;h2&gt;
  
  
  Crochet
&lt;/h2&gt;

&lt;p&gt;I started with the crochet because I figured I had the most experience in it, knew that it would take time, and that it was foundational for all the other pieces. I built a small prototype to test my initial design out:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cnJEHVvd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/as5b5bxzjl9dob1bdgum.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cnJEHVvd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/as5b5bxzjl9dob1bdgum.jpg" alt="prototype angel" width="500" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once I was satisfied with the overall shape of the prototype, I then proceeded to make a bigger version. Determining the scale for the angel was more complicated than I anticipated, I knew the tree would be 6ft but that didn't really help me work out how big the angel should be.&lt;/p&gt;

&lt;p&gt;The first angel that I started making, I determined was way too small after seeing what two lights would look like inside.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cEcpQ-I1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/zpnmlu0cnivtlfhn0f84.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cEcpQ-I1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/zpnmlu0cnivtlfhn0f84.jpg" alt="scaling crochet is hard" width="500" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Progress on the second angel was much better but I got to a difficult stage where the angel just looked like a jellyfish!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yzZH0Nd2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yfsb6wdbjbnmz1uv4qts.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yzZH0Nd2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yfsb6wdbjbnmz1uv4qts.jpg" alt="angel looks like a jellyfish" width="500" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After crocheting her a head (and a halo) she looked much more angel like. I was happy that I could move on to the next stage, electronics!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ywNAT3fm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9sr1t8od1enzano13ipk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ywNAT3fm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9sr1t8od1enzano13ipk.jpg" alt="completed angel" width="500" height="667"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Electronics
&lt;/h2&gt;

&lt;p&gt;I'm going to prefix the next section with this is my first electronics project. I learned a lot throughout this process.&lt;/p&gt;

&lt;p&gt;I chose the &lt;a href="https://shop.pimoroni.com/products/adafruit-feather-huzzah-with-esp8266-wifi"&gt;adafruit huzzah esp8226&lt;/a&gt; board, it's designed to be small and light and has integrated wifi, but most importantly &lt;a href="https://twitter.com/thisisjofrank"&gt;@thisisjofrank&lt;/a&gt; told me to get it. I also went with some &lt;a href="https://shop.pimoroni.com/products/flora-rgb-smart-neo-pixel-version-2-sheet-of-20"&gt;adafruit flora neopixel v2&lt;/a&gt; for the lights, they're super bright and individually addressable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/thisisjofrank"&gt;@thisisjofrank&lt;/a&gt; also gave me a whole bunch of copper wire so I could connect all my components. I also learnt that we have an electronics club in the office, so I could borrow a soldering iron (and guidance) from my colleague Callum.&lt;/p&gt;

&lt;p&gt;I haven't used a soldering iron since secondary school, which was at least 15 years ago! I found it difficult ensuring that all six cables were threaded into and out of each pixel. I ended up taping them in place on an old amazon packaging so that I could move it around more easily and not damage any surfaces with hot solder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vgMe7ln7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1llo4s1v0yxkiun0v18s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vgMe7ln7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1llo4s1v0yxkiun0v18s.jpg" alt="first soldering attempt" width="500" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My first pass at soldering everything concluded with only the first 5 pixels lighting up. I spotted one of the cables had fallen out of the sixth pixel so wasn't actually connected. A quick return to the soldering iron fixed that and then all my lights were operational! 🎉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WxeA7A4T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/05undjwl2822bqyh78pp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WxeA7A4T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/05undjwl2822bqyh78pp.jpg" alt="second soldering attempt" width="500" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the solder had set, I cut back any straggling cables and covered the whole thing in &lt;a href="https://www.amazon.co.uk/Sugru-Mouldable-Glue-Original-Formula/dp/B008MIRQUE/"&gt;sugru&lt;/a&gt;. Sugru is a moldable plastic,  I could cover all my exposed cables and they'd not only be more robust but also be fully insulated. I was worried that putting any exposed cabling in cotton yarn could be a fire hazard 🔥 and I &lt;em&gt;really&lt;/em&gt; didn't want to be the person who set fire to the office Christmas tree!&lt;/p&gt;

&lt;p&gt;The next step was to sew the electronics into the body of the angel. I turned the body inside out and carefully stitched the wiring into the body. The hardest part here was turning the angel back the right way with all the cables set up! It made a horrifying crunch noise but everything survived okay!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gS78gKsv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/pmk3985iteuw6tc6vix1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gS78gKsv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/pmk3985iteuw6tc6vix1.jpg" alt="horrific sewn in components image" width="500" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, it was time to write the code for the microcontroller.&lt;/p&gt;
&lt;h2&gt;
  
  
  Microcontroller code
&lt;/h2&gt;

&lt;p&gt;I split this section into two chunks - I needed to change the pixel colours, then I needed to connect to a &lt;a href="https://pusher.com/channels?utm_source=dev-to&amp;amp;utm_medium=organic&amp;amp;utm_campaign=danielles-post&amp;amp;utm_content=pusher-angel"&gt;Pusher Channel&lt;/a&gt; using websockets directly and receive colour changing events.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;Firstly, I needed to be able to connect to my board from my MacBook. This required me to install the &lt;a href="https://www.arduino.cc/en/main/software"&gt;Arduino IDE&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once that was set up, I needed to add my ESP8266 board in the preferences and adding &lt;code&gt;http://arduino.esp8266.com/stable/package_esp8266com_index.json&lt;/code&gt; to the additional board managers. This meant I could then select this board in tools - boards and ensure any code would compile for that specifically. I also had to install the &lt;a href="https://learn.adafruit.com/adafruit-feather-huzzah-esp8266/using-arduino-ide"&gt;driver for the board on my MacBook&lt;/a&gt;. After that I could select the right port in the tools -&amp;gt; port, before I think it was just trying to send my microcontroller code to my MacBook USB adapter which obviously was never going to work! 😆&lt;/p&gt;
&lt;h3&gt;
  
  
  NeoPixel Colours
&lt;/h3&gt;

&lt;p&gt;Next, I needed to install the Adafruit NeoPixel library. You can do this by clicking Tools -&amp;gt; Manage Libraries and searching for the NeoPixel library. Adafruit have written a bunch of example scripts you can use to get up and running fast. If you tap File -&amp;gt; Examples -&amp;gt; scroll down to your added libraries and the Adafruit NeoPixel section -&amp;gt; &lt;a href="https://github.com/adafruit/Adafruit_NeoPixel/blob/master/examples/strandtest/strandtest.ino"&gt;strandtest&lt;/a&gt;. The strandtest goes through a bunch of colours and settings. You need to provide how many pixels you have, and the pin you've connected your NeoPixels to on the board and it's a quick way to ensure your lights are all operational!&lt;/p&gt;

&lt;p&gt;Using the &lt;a href="https://github.com/adafruit/Adafruit_NeoPixel/blob/master/examples/strandtest/strandtest.ino"&gt;example code&lt;/a&gt; is great because you can see how Adafruit change the lights to do what they want. I copied across the function that would let me change all the lights to a given colour &lt;code&gt;colorWipe&lt;/code&gt;, and &lt;code&gt;rainbow()&lt;/code&gt; so I could enable a special mode ✨&lt;/p&gt;
&lt;h3&gt;
  
  
  Websockets
&lt;/h3&gt;

&lt;p&gt;The next part of the puzzle was to get the board to connect to the Internet. I looked at who else had solved this problem; I loaded up the examples but this time we had to look at the &lt;code&gt;esp8226&lt;/code&gt; examples. I used the BasicHttpClient example as originally I was looking to make a HTTP request. This had the code I needed to connect to the WiFi. Later, I found another example that looped in the setup until it the wifi was connected before it would move on. As I was using lights, I figured I could use them to let me know when I was connected too!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ssid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SSID_HERE"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"WIFI_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;ESP8266WiFiMulti&lt;/span&gt; &lt;span class="n"&gt;WiFiMulti&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;115200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;//make the lights red when it's not connected&lt;/span&gt;
  &lt;span class="n"&gt;colorWipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&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="mi"&gt;0&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="n"&gt;WiFi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WIFI_STA&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;WiFiMulti&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addAP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ssid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WiFiMulti&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;WL_CONNECTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;delay&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="c1"&gt;//make the lights green when it's connected to the internet&lt;/span&gt;
  &lt;span class="n"&gt;colorWipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&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="mi"&gt;255&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="mi"&gt;10&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;Now we know we're happily connected to the Internet, we needed to work out how to use websockets! There's a popular library from &lt;a href="https://github.com/Links2004/arduinoWebSockets"&gt;Links2004 for arduino sockets&lt;/a&gt;. I downloaded the repository and imported it as a library by going to the menu - Sketch - Include Library - add .ZIP library and selected the downloaded repo.&lt;/p&gt;

&lt;p&gt;Like all the other libraries we've used today, this also had a &lt;a href="https://github.com/Links2004/arduinoWebSockets/blob/master/examples/esp8266/WebSocketClient/WebSocketClient.ino"&gt;WebSocketClient example&lt;/a&gt;. I could look at how their code worked and copy paste what I needed for my example!&lt;/p&gt;

&lt;p&gt;I needed to follow the &lt;a href="https://pusher.com/docs/channels/library_auth_reference/pusher-websockets-protocol?utm_source=dev-to&amp;amp;utm_medium=organic&amp;amp;utm_campaign=danielles-post&amp;amp;utm_content=pusher-angel"&gt;Pusher Channels protocol doc&lt;/a&gt; to connect to a Channels websocket however, every time I tried to run this on my device it just wouldn't connect. I needed to be able to see some  debug messages so I could fix any issues.&lt;/p&gt;

&lt;p&gt;In order to do this, I added the following line to my setup code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setDebugOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As well as setting the variable in code, you also need to configure the Arduino IDE to enable debug messages. You need to set tools - debug port to Serial (not disabled). You also need to set change the debug level (in the same menu tree). I setting with the most letters and I then saw a great deal more information in my Serial monitor!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QnecxvhB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kf4hlnbyeffrtyzpgtes.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QnecxvhB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kf4hlnbyeffrtyzpgtes.png" alt="screenshot of debug menu" width="880" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I learned that the websocket library already prefixed the socket address, so my connection string needed to look as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ws-CLUSTER.pusher.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/app/APP_KEY?client=arduino&amp;amp;version=0.0.1&amp;amp;protocol=7"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that set up, I could see in my Serial monitor that eventually it would connect successfully!&lt;/p&gt;

&lt;p&gt;The next step to using Channels is to subscribe to a channel, which I was going to call &lt;code&gt;angel&lt;/code&gt;. Reading the docs again, I could write the JSON needed to send a subscription event myself and send it through the websocket :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;event&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;pusher:subscribe&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;: {&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;channel&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;angel&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;} }"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;webSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sendTXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I made sure to send this event as soon as I get the connect event to the websocket. This means that I could then listen to any events that come through. &lt;a href="https://pusher.com/docs/channels/library_auth_reference/pusher-websockets-protocol?utm_source=dev-to&amp;amp;utm_medium=organic&amp;amp;utm_campaign=danielles-post&amp;amp;utm_content=pusher-angel#double-encoding"&gt;Pusher Channels&lt;/a&gt; sends the payload in JSON format. The JSON looks something like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"event"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"new-colour"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;responseColour&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;255,204,0&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;255&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;g&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;204&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;b&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"channel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"angel"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I could have spent time working out how to parse the request myself, or I could use yet another library! I chose &lt;a href="https://github.com/bblanchon/ArduinoJson/"&gt;Arduino JSON&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I struggled a little as the &lt;code&gt;data&lt;/code&gt; returned in the event is encoded as a string, and I needed to deserialize that using a second &lt;code&gt;DynamicJsonDocument&lt;/code&gt;. I had intended to send the colour value as a rgb payload but I soon learned it was very complicated to split a string on a delimiter in arduino land, and it was much easier to change the API to send the values in separate R G B values. My code now looked like the following :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;DynamicJsonDocument&lt;/span&gt; &lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;DynamicJsonDocument&lt;/span&gt; &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;deserializeJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"event"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"new-colour"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;deserializeJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;colour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"responseColour"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colour&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;Once I'd mastered how to get all the data I cared about in the event, I wrote a big if statement to check what kind of event I'd got, whether it was a standard rgb colour or a special mode. If it was a standard RGB value I could parse it straight to the lights to render using the &lt;code&gt;colorWipe&lt;/code&gt; function we learned earlier.&lt;/p&gt;

&lt;p&gt;Or could I?&lt;/p&gt;

&lt;p&gt;This is where I learned that dealing with colour is hard. Different devices render colour differently. Where my computer screen displays #ffcc00 as a beautiful yellow, my NeoPixels were displaying them as a washed out yellow. I did some googling to work out why this was happening and stumbled upon &lt;a href="http://jamie-wong.com/post/color/"&gt;this brilliant explanation that explains the issue very thoroughly&lt;/a&gt;. It looked like I was going to have to write a complicated algorithm to translate my colour into something the NeoPixel could display better :(&lt;/p&gt;

&lt;p&gt;But how did the Adafruit &lt;code&gt;rainbow&lt;/code&gt; function the example code had work? Their colours never appeared washed out! Were they doing something I could use? When I looked into it a bit more, they were using this mysterious &lt;code&gt;gamma32()&lt;/code&gt; function. Reading from their &lt;a href="https://cdn-learn.adafruit.com/downloads/pdf/adafruit-neopixel-uberguide.pdf"&gt;uberguide&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Something you might observe when working with more nuanced color changes is that things may appear overly bright&lt;br&gt;
or washed-out. It’s generally not a problem with simple primary and secondary colors, but becomes more an issue with&lt;br&gt;
blends, transitions, and the sorts of pastel colors you might get from the ColorHSV() function. Numerically the color&lt;br&gt;
values are correct, but perceptually our eyes make something different of it, as explained in this&lt;br&gt;
guide &lt;a href="https://adafru.it/w2B"&gt;https://adafru.it/w2B&lt;/a&gt;.&lt;br&gt;
The gamma32() function takes a packed RGB value (as you might get out of Color() or ColorHSV()) and filters the result&lt;br&gt;
to look more perceptually correct.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Perfect! This is exactly what I needed to solve this problem! &lt;a href="https://github.com/daniellevass/pusher-christmas-angel/blob/master/arduino_code/arduino_code.ino"&gt;My arduino code&lt;/a&gt; was complete 🌟&lt;/p&gt;

&lt;h2&gt;
  
  
  Web App
&lt;/h2&gt;

&lt;p&gt;The final part of this project required a web application to enable other people to easily change the colours.&lt;/p&gt;

&lt;p&gt;One of my other colleagues has recently built something similar to demonstrate how others could use a &lt;a href="https://pusher.com/channels?utm_source=dev-to&amp;amp;utm_medium=organic&amp;amp;utm_campaign=danielles-post&amp;amp;utm_content=pusher-angel"&gt;Pusher Channel&lt;/a&gt; to rate dogs on the Internet in real time. They kindly showed me how it was built so I could copy everything to build my web app to control my angel.&lt;/p&gt;

&lt;p&gt;I &lt;a href="https://github.com/daniellevass/pusher-christmas-angel/blob/master/index.html"&gt;built a basic website&lt;/a&gt; using bootstrap, to enable people to provide a hex colour, select a standard colour, or select a special mode and send it to the angel!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9zvx_2Aa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tg4975hs1q4b0zyckt7p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9zvx_2Aa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tg4975hs1q4b0zyckt7p.png" alt="screenshot of the complete app" width="880" height="654"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pusher.com/channels?utm_source=dev-to&amp;amp;utm_medium=organic&amp;amp;utm_campaign=danielles-post&amp;amp;utm_content=pusher-angel"&gt;Pusher Channels&lt;/a&gt; don't allow clients to send events unless they're authenticated and using either a private or presence channel. I didn't want to authenticate people to use this web app, so instead &lt;a href="https://github.com/daniellevass/pusher-christmas-angel/blob/master/api/colour.js"&gt;I needed to create my own node api which could then trigger the events&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I was also recommended a service provider called &lt;a href="https://zeit.co"&gt;zeit&lt;/a&gt; to deploy the web app too. They'd also be able to host my API for free too as a &lt;a href="https://zeit.co/docs/v2/serverless-functions/introduction/"&gt;serverless function&lt;/a&gt;! After I installed their &lt;a href="https://zeit.co/download"&gt;npm cli&lt;/a&gt; I could type &lt;code&gt;now&lt;/code&gt; into my terminal to deploy my website! I configured some &lt;a href="https://zeit.co/docs/v2/environment-variables-and-secrets/?query=environment#"&gt;environment variables&lt;/a&gt; so that I could open source the code without any fear that other people would be able to use my &lt;a href="https://pusher.com/channels?utm_source=dev-to&amp;amp;utm_medium=organic&amp;amp;utm_campaign=danielles-post&amp;amp;utm_content=pusher-angel"&gt;Pusher Channel&lt;/a&gt; instance.&lt;/p&gt;

&lt;p&gt;I also added some google analytics tracking to the app. I'm interested in knowing how many people are using it, and what colours you're sending her! I'll maybe do a follow up with what we learned from this!&lt;/p&gt;

&lt;p&gt;After some user testing with meetups in the office, I added &lt;a href="https://pusher.com/channels?utm_source=dev-to&amp;amp;utm_medium=organic&amp;amp;utm_campaign=danielles-post&amp;amp;utm_content=pusher-angel"&gt;Pusher Channels&lt;/a&gt; into the web app to listen for the events. This means everyone currently watching the web page can also see what events are being sent. This means you know if someone else is "hilariously" setting the lights to #000000 (which turns the lights off), and not that the angel has broken!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4qPop9S4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/s0msep2pzyktqqhzl4bo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4qPop9S4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/s0msep2pzyktqqhzl4bo.jpg" alt="picture of the zeit meetup in the office" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Finishing
&lt;/h2&gt;

&lt;p&gt;I feel like this has been a massively over engineered solution to the "crochet me a Christmas tree angel" problem. I'm very happy that she's now finished and I'm even happier that she's brought other people joy in the office!&lt;/p&gt;

&lt;p&gt;I hope you learned something from this blog. My source code for the entire project is available at &lt;a href="https://github.com/daniellevass/pusher-christmas-angel"&gt;https://github.com/daniellevass/pusher-christmas-angel&lt;/a&gt;. And if you're going to attend any of our meetups in December please make sure you check it out and play around yourself :)&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>microcontroller</category>
      <category>arduino</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
