Jekyll2023-10-30T06:54:47+00:00https://www.shawenyao.com/feed.xmlWenyaoA drifter, off to see the worldWhere is My Package2023-10-30T00:00:00+00:002023-10-30T00:00:00+00:00https://www.shawenyao.com/Where-Is-My-Package<p>An Amazon, UPS, and Leasing Office Mystery</p>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Where Is My Package/1.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Where Is My Package/2.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Where Is My Package/3.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Where Is My Package/4.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Where Is My Package/5.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Where Is My Package/6.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Where Is My Package/7.png" />
</div>An Amazon, UPS, and Leasing Office MysteryDouble Pack2023-08-25T00:00:00+00:002023-08-25T00:00:00+00:00https://www.shawenyao.com/Double-Pack<p>A Walgreens Mystery</p>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Double Pack/1.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Double Pack/2.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Double Pack/3.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Double Pack/4.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Double Pack/5.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Double Pack/6.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Double Pack/7.png" />
</div>A Walgreens MysteryLego Baby Bottle Stand2023-04-26T00:00:00+00:002023-04-26T00:00:00+00:00https://www.shawenyao.com/Lego-Baby-Bottle-Stand<p>Mommy is the best - period. Meanwhile, daddy has been trying to help.</p>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Lego Baby Bottle Stand/final.jpg" />
</div>
<h2 id="instructions">Instructions</h2>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Lego Baby Bottle Stand/1_2x.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Lego Baby Bottle Stand/2_2x.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Lego Baby Bottle Stand/3_2x.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Lego Baby Bottle Stand/4_2x.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Lego Baby Bottle Stand/5_2x.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Lego Baby Bottle Stand/6_2x.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Lego Baby Bottle Stand/7_2x.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Lego Baby Bottle Stand/8_2x.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Lego Baby Bottle Stand/9_2x.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Lego Baby Bottle Stand/10_2x.png" />
</div>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Lego Baby Bottle Stand/11_2x.png" />
</div>
<p>Instructions created with <a href="https://www.bricklink.com/v3/studio/download.page">Bricklink Studio</a>. To download a PDF copy, click <a href="https://shawenyao.github.io/Photos/Lego%20Baby%20Bottle%20Stand/bottle%20stand.pdf">here</a>.</p>Mommy is the best - period. Meanwhile, daddy has been trying to help.Hello Weiyi2023-03-20T00:00:00+00:002023-03-20T00:00:00+00:00https://www.shawenyao.com/Hello-Weiyi<p>It’s our pleasure to meet you.</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/Random/ws.jpg" />
</p>
<p><br /></p>
<p>Hello Weiyi,</p>
<p>On a sunny afternoon a little less than 10 months ago, we became aware of your existence. We were thrilled to say the least. A tad uneasy, too. As clueless as we were, we then set off on a journey to prepare ourselves for your arrival. That brings us to, well, today.</p>
<p>Today, we welcome you to this world.</p>
<p>It is a beautiful world. One full of natural wonders and man-made miracles. Right off the bat, you are already a descendant of a 13.8-billion-year-old universe,<sup>1</sup> a 4.5-billion-year-old planet,<sup>2</sup> and a 6000-year-old civilization.<sup>3</sup> By the time you read this, a lot more surely will have changed. Will humans have become inter-planetary? How much faster will computers run? Will cars be driving themselves, finally? Will you, perhaps, become part of the change, just like we all did today?</p>
<p>Today, we welcome you as the newest member of our small but growing family on Harvey Drive. Mom and Dad are what you might call nice people. Average, nice people. We came from a country across the Pacific Ocean, where your grandparents call home. There’s also Disney the tabby cat, who joined us about 3 years earlier than you did. All of us enjoy keeping each other company, and we will make sure you are no exception.</p>
<p>It is going to be a while before you can make a living on your own - and that’s okay. We as a species are all beneficiaries of our extended childhood. It means possibilities. So, so many of them. There is knowledge to gain, skills to master, places to visit, books to read, music to listen to, movies to watch, games to play… Though we will guide you on what to try first, we want to listen to you. In time, you will learn to make the best arrangements for yourself and take responsibility for your actions. It is your life, after all. As much as we applaud an exciting, accomplished life, a simple, uneventful one can be just as commendable. All we ask of you is to treat everyone kindly and live every day to the fullest.</p>
<p>It is not always going to be easy. You will meet challenges. Insurmountable, hopeless predicaments. There will be pains. Excruciating, heart-wrenching days. You will make choices. Hard, unpopular decisions. But whatever you face and however you deal with it, please remember that on this day, you were born with our utmost love, care and support.</p>
<p>Yours,</p>
<p>Mom and Dad</p>
<p><br /></p>
<p><sup>1</sup> Universe, <em>Wikipedia</em>, <a href="https://en.wikipedia.org/wiki/Universe">https://en.wikipedia.org/wiki/Universe</a>, accessed March 2023.</p>
<p><sup>2</sup> Earth, <em>Wikipedia</em>, <a href="https://en.wikipedia.org/wiki/Earth">https://en.wikipedia.org/wiki/Earth</a>, accessed March 2023.</p>
<p><sup>3</sup> Civilization, <em>Wikipedia</em>, <a href="https://en.wikipedia.org/wiki/Civilization">https://en.wikipedia.org/wiki/Civilization</a>, accessed March 2023.</p>It’s our pleasure to meet you.BART Platform Sign Portable2023-02-08T00:00:00+00:002023-02-08T00:00:00+00:00https://www.shawenyao.com/BART-Platform-Sign-Portable<p>An authentic, desktop BART experience.</p>
<div align="center">
<img src="https://shawenyao.github.io/Photos/BART-OLED/demo.gif" style="width:100%;height:auto;" />
</div>
<p><em>BART Platform Sign Portable in action, train arriving.</em></p>
<p><br /></p>
<p>I like commuting by BART. It’s fast, (relatively) reliable and (mostly) stress-free. Indeed, for the price, there isn’t really a whole lot to complain about. That said, if there has to be one, for me it’s probably going to be about the long wait between trains for some lines. Adding more trains is an obvious solution to the problem, albeit a rather expensive one. Timing the train is another, a much more feasible one at that. In fact, thanks to the BART app or even Google Maps, arrival and schedule info is readily available to inform trip planning. However, sometimes I just wish that there were a BART platform sign right outside my bedroom window. Yes, that would be so cool. Well, so unrealistic, too. Fortunately, the next best thing is very much doable with a little help from a Raspberry Pi Pico W.</p>
<h2 id="bart-platform-sign-the-original">BART Platform Sign, the Original</h2>
<p>Behold the original, real BART platform sign, a piece of display that looks all too familiar to some 145,700 riders (as of <a href="https://en.wikipedia.org/wiki/Bay_Area_Rapid_Transit">Q3 2022</a>) everyday -</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/BART-OLED/1.jpg" width="48%" />
<img src="https://shawenyao.github.io/Photos/BART-OLED/2.jpg" width="48%" />
</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/BART-OLED/3.jpg" width="48%" />
<img src="https://shawenyao.github.io/Photos/BART-OLED/4.jpg" width="48%" />
</p>
<p><em>Four types of platform sign layouts. Top left: estimated wait time; top right: BART Service Advisories; bottom left: train arriving; bottom right: digital clock.</em></p>
<p>If you stare at it for a while, a pattern begins to emerge. Generally, the sign loops through four different layouts. First, there’s the estimated wait time screen between trains, which can span multiple screens by itself. This is often followed by a second type of layout, BART Service Advisories, usually regarding an announcement of a train outage, cancellation, or just a friendly reminder from the police asking you to pay attention to your belongings. Third, a full-screen display of the destination kicks in when a train enters the platform. Finally, a digital clock pops up from time to time. They are all useful in some way, with the possible exception of the second one which isn’t that informative in my opinion.</p>
<h2 id="connecting-a-display">Connecting a Display</h2>
<p>There are many affordable options when it comes to adding a display to a Raspberry Pi. For example, this 0.96-inch one can be had for about <a href="https://www.amazon.com/gp/product/B09T6SJBV5/">$3 apiece</a>. It features an 128x64 OLED display and should provide enough screen real estate for all the important stuff to be rendered on a single screen. For a detail instruction on how to use the display, <a href="https://www.tomshardware.com/how-to/oled-display-raspberry-pi-pico">here</a> is an excellent guide from Tom’s Hardware.</p>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Raspberry Pi/picow&oled.png" />
</div>
<p><em>Raspberry Pi Pico W and OLED display. Left: Raspberry Pi Pico W; right: 128x64 OLED display. Image created by author on Google Slides.</em></p>
<h2 id="getting-real-time-departure-estimates">Getting Real-Time Departure Estimates</h2>
<p>BART offers real-time departure estimates via its <a href="https://api.bart.gov/">API</a>. A simple HTTPS request to:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://api.bart.gov/api/etd.aspx?cmd=etd&orig={station}&dir={direction}&key={key}&json=y
</code></pre></div></div>
<p>will result in a list of incoming trains for a given station in a given direction being returned. This would have been a breeze if not for one caveat. For some reason, the official <code class="language-plaintext highlighter-rouge">urequests</code> library that comes with the MicroPython firmware has HTTP/1.0 hardcoded. Cloudflare, by which the domain <code class="language-plaintext highlighter-rouge">bart.gov</code> is protected, doesn’t like it very much and will instantly shut down any connection attempt as such. This calls for a modification in the <code class="language-plaintext highlighter-rouge">request()</code> function in <code class="language-plaintext highlighter-rouge">urequests</code>. Thankfully, after playing with the script, I realize that the fix could be something as simple as changing <a href="https://github.com/micropython/micropython-lib/blob/master/python-ecosys/urequests/urequests.py#L94">line 94</a> from:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">s</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="sa">b</span><span class="s">"%s /%s HTTP/1.0</span><span class="se">\r\n</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">method</span><span class="p">,</span> <span class="n">path</span><span class="p">))</span>
</code></pre></div></div>
<p>to:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">s</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="sa">b</span><span class="s">"%s /%s HTTP/1.1</span><span class="se">\r\n</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">method</span><span class="p">,</span> <span class="n">path</span><span class="p">))</span>
</code></pre></div></div>
<p>in addition to a few touches at the end to parse the JSON response correctly.</p>
<h2 id="controlling-text-sizes">Controlling Text Sizes</h2>
<p>Without an operating system, changing text fonts or sizes isn’t as straightforward. To solve the problem, Peter Hinch has developed a wonderful <a href="https://github.com/peterhinch/micropython-font-to-py">solution</a>, which to my understanding involves some sort of character-by-character bitmap of the font that are cleverly encoded in a bytearray form. Once the <code class="language-plaintext highlighter-rouge">Writer</code> class is initialized with such bytearray:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># various fonts
</span><span class="n">font6_writer</span> <span class="o">=</span> <span class="n">writer</span><span class="p">.</span><span class="n">Writer</span><span class="p">(</span><span class="n">oled</span><span class="p">,</span> <span class="n">font6</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">font10_writer</span> <span class="o">=</span> <span class="n">writer</span><span class="p">.</span><span class="n">Writer</span><span class="p">(</span><span class="n">oled</span><span class="p">,</span> <span class="n">font10</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">courier20_writer</span> <span class="o">=</span> <span class="n">writer</span><span class="p">.</span><span class="n">Writer</span><span class="p">(</span><span class="n">oled</span><span class="p">,</span> <span class="n">courier20</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
</code></pre></div></div>
<p>it can then be used to print any arbitrary text to the OLED screen:</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/BART-OLED/arriving.jpg" width="48%" />
<img src="https://shawenyao.github.io/Photos/BART-OLED/schedule.jpg" width="48%" />
</p>
<p><em>An OLED screen displaying texts in different font sizes. Left: train arriving; right: estimated wait time.</em></p>
<h2 id="displaying-time">Displaying Time</h2>
<p>A Raspberry Pi Pico W doesn’t have an internal battery to keep the clock running constantly, so we will need an authority to tell time upon boot up. This requires a call to <code class="language-plaintext highlighter-rouge">worldtimeapi.org</code>, where it will automatically deal with time zone conversion depending on the user’s IP:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://worldtimeapi.org/api/ip
</code></pre></div></div>
<p>or fix the time zone with something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://worldtimeapi.org/api/timezone/America/Los_Angeles
</code></pre></div></div>
<p>The response contains a JSON with all the information necessary to set the initial value of the onboard real time clock on a Raspberry Pi Pico W.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># set initial time based on worldtimeapi.org
</span><span class="n">rtc</span> <span class="o">=</span> <span class="n">machine</span><span class="p">.</span><span class="n">RTC</span><span class="p">()</span>
<span class="n">rtc</span><span class="p">.</span><span class="n">datetime</span><span class="p">((</span><span class="n">year</span><span class="p">,</span> <span class="n">month</span><span class="p">,</span> <span class="n">day</span><span class="p">,</span> <span class="n">weekday</span><span class="p">,</span> <span class="n">hours</span><span class="p">,</span> <span class="n">minutes</span><span class="p">,</span> <span class="n">seconds</span><span class="p">,</span> <span class="n">subseconds</span><span class="p">))</span>
</code></pre></div></div>
<p>After initialization, <code class="language-plaintext highlighter-rouge">rtc.datetime()</code> will return the current date and time.</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/BART-OLED/clock.jpg" width="48%" />
</p>
<p><em>An OLED screen displaying a digital clock.</em></p>
<h2 id="putting-it-all-together">Putting It All Together</h2>
<video src="https://shawenyao.github.io/Photos/BART-OLED/demo.mp4" controls="controls" width="100%"></video>
<p><em>BART Platform Sign Portable in action, train arriving.</em></p>
<h2 id="appendix">Appendix</h2>
<h3 id="try-it-yourself">Try It Yourself</h3>
<p><a href="https://github.com/shawenyao/bart-oled">https://github.com/shawenyao/bart-oled</a></p>
<p><br /></p>
<p>Update October 12, 2023: As of September 2023, <a href="https://www.bart.gov/about/projects/legacy">legacy BART trains</a> (the ones with 2 doors per car instead of 3) are no longer in service. As a result, where it used to say “2-door” or “3-door” on the platform sign now displays the color of the line.</p>An authentic, desktop BART experience.A Distributed Motion-Controlled Lighting System2023-01-09T00:00:00+00:002023-01-09T00:00:00+00:00https://www.shawenyao.com/A-Distributed-Motion-Controlled-Lighting-System<p>Fiat lux.</p>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Raspberry Pi/4b&picow.png" />
</div>
<p><em>Image created by author on Google Slides. Left: Raspberry Pi 4 Model B; right: Raspberry Pi Pico W.</em></p>
<p><br /></p>
<p>I have been looking for the optimal, most hassle-free way to control my stairs light. The electrical engineers who helped design the apartment apparently have put a great deal of thought into it, too. The dome light above the stairs can be turned on or off by two switches on both ends in an “<a href="https://en.wikipedia.org/wiki/Exclusive_or">exclusive or (XOR)</a>” fashion. The intention, if I may speculate, is for the users to flip one switch (when going either up or down) to turn the light on, than the other (when finished) to turn it off. This is fine for most use cases, but it’s not difficult to think of a few occasions where a handsfree approach would be preferred. While <a href="https://www.shawenyao.com/Voice-Controlled-Raspberry-Pi/">voice control</a> already works decently well, a motion-controlled solution is arguably the more natural way of interacting with the light in this case. The system should be able to monitor movement on the stairs, switching the light on or off accordingly. High energy efficiency would be a nice feature as well, so it can last for days on a power bank. Ideally, I would also like to have on-the-fly configurability without rewiring, and some degree of resistance to unintended distractions (yes, I am looking at my <a href="https://www.shawenyao.com/Cat-in-Black/">cat</a>).</p>
<h2 id="smart-home-basics">Smart Home Basics</h2>
<p>For this project, various <a href="https://en.wikipedia.org/wiki/Raspberry_Pi">Raspberry Pi</a> computers will be utilized. The 4th generation, Raspberry Pi 4 Model B, is by far the most powerful Raspberry Pi with a quad-core CPU clocking in at 1.5GHz. The newest entry to the Raspberry Pi family, Pico W, is a microcontroller capable of running <a href="[https://en.wikipedia.org/wiki/MicroPython](https://micropython.org/)">MicroPython</a> and accessing the Internet, and will be serving as the bridge between the main Raspberry Pi unit and the motion sensor.</p>
<p>Smart plugs are next. Essentially, they are Wi-Fi-enabled switches that can be turned on or off via an API call, rendering “non-smart” devices such as a floor lamp “smart”. For example, TP-Link offers many choices under the brand <a href="https://www.kasasmart.com/us/products/smart-plugs">Kasa</a>. Programmatic control of the Kasa smart plugs is made possible by the <a href="https://github.com/python-kasa/python-kasa">python-kasa</a> library.</p>
<p>Last but certainly not least, there’s the motion sensor itself. The HC-SR505 sensor, a type of <a href="https://en.wikipedia.org/wiki/Passive_infrared_sensor">passive infrared (PIR) sensor</a> for instance, can get the job done nicely.</p>
<h2 id="design-1-motion-sensing-101">Design 1: Motion Sensing 101</h2>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Light/1.png" />
</div>
<p>The most straightforward solution is probably a two-Pi system. The first unit, a Pico W connected to a PIR motion sensor and placed at the bottom of the stairs, is responsible for detecting motion. If and when it does, the microcontroller sends a signal wirelessly to the second unit, a Raspberry Pi 4 listening to such request via a <a href="https://flask.palletsprojects.com/">Flask</a> server, who then turns the light on, waits a bit and switches it off. A detailed guide on how to make a Pico work with a HC-SR505 sensor can be found on <a href="https://www.freva.com/pir-motion-sensor-on-a-raspberry-pi-pico/">freva.com</a>.</p>
<p>From a human-machine interface standpoint, anyone who wishes to go upstairs simply need to proceed as usual. The action will be captured at the very beginning of the climb so lighting will hopefully be available for the majority of the journey. The duration of the light is controlled by the server side and should be reasonably long (say a minute) to allow sufficient time for climbing before darkness falls again. When it times out, the server tells the light to power off - again, no human intervention needed.</p>
<p>Additionally, it’s worth noting that the second Pi is a must currently because the MicroPython environment available on the Pico W has yet to provide official support for the python-kasa library. This is not necessarily a bad thing. In fact, it must be taken into account that upgrading code on a Raspberry Pi Pico W is quite troublesome. It requires physically connecting the board to a computer, launching an editor, editing and saving. Therefore, it’s advisable to keep the logic on the Pico W as simple and generic as possible, and leave the more complicated part to the more powerful (and better-supported) Raspberry Pi 4.</p>
<h2 id="design-2-distributed-motion-sensors">Design 2: Distributed Motion Sensors</h2>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Light/2.png" />
</div>
<p>Now, the light turns on when I go upstairs - that’s all good. But sooner or later, I might have to come downstairs and wish the light turned on as well. So comes a third unit, another Raspberry Pico W placed at the top of the stairs. Everything that worked before should continue to work with the same setup and the same code, only that now there are two triggers. When I go upstairs, the bottom sensor detects me and turns on the light. Granted, in a few seconds, the sensor upstairs also sees me and wants to turn on the light, but it doesn’t matter as the light is already on (and vice versa). Moreover, the system can scale easily. Any number of additional Pico Ws/PIR sensors can be added or removed without any major effort.</p>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Light/problem.png" />
</div>
<p>There is a problem with such design, however. The fact that the two sensors work <em>independently</em> and <em>memorylessly</em> brings a serious downside. If I decide to stay on the stairs, there’s no way for the system to extend the duration of the lighting. For example, after my movement is picked up by the first sensor, the light is set to stay on for a predetermined amount of time (however generous that amount is). Even if another sensor (or the same one, for the matter) detects any further motion, its signal will be useless since it merely tries to turn on a light that is already on, or off when it’s already off. The inconvenience calls for a new round of upgrade.</p>
<h2 id="design-3-coordinating-the-sensors">Design 3: Coordinating the Sensors</h2>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Light/3.png" />
</div>
<p>In the final design, the two Pico Ws no longer assume to role of triggering the logic to control the light. Instead, they focus on one thing and one thing alone: sending the signals detected by the PIR sensor to the server. The server logs the timestamp at which the last motion is reported. A new process on the Raspberry Pi 4, an infinite loop, repeatedly triggers a piece of logic that compares the current time with the timestamp of last motion. If the difference is within the duration for which the light is meant to be turned on but the light happens to be off, it turns the light on. If the difference is greater than the duration but the light is on, it turns it off. In other words, the system has <em>memory</em> now. As a result, any detected motion will reset the countdown to lights out, enabling a much more intuitive user experience.</p>
<h2 id="putting-it-all-together">Putting It All Together</h2>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Light/demo.gif" style="width:100%;height:auto;" />
</div>
<p>From my own experience using it, the PIR sensor proves to be sensitive enough to any real human movement (true positive). On the contrary, stairs light randomly turning on, especially at night, has become a bigger concern. Is it the cat? Should I call 911? Or, could it simply be a false positive? None of which can be called a pleasant thought at 2 a.m. The issue haunted me for a couple of nights, until -</p>
<h2 id="life-hacks">Life Hacks</h2>
<div align="center">
<img src="https://shawenyao.github.io/Photos/Light/hack.jpg" />
</div>
<p><em>Left: Raspberry Pi Pico W and HC-SR505 sensor; right: Raspberry Pi Pico W and HC-SR505 sensor with a scroll of paper.</em></p>
<p>To my great surprise, a simple scroll of paper works wonders at getting rid of the false alarms, by virtue of limiting the range of the sensor’s visibility. Furthermore, ever since I accidentally left it pointing upward, the system has literally turned a blind eye to my cat’s loitering, an unexpected yet delightful side effect that brings closure to this matter.</p>
<h2 id="appendix">Appendix</h2>
<h3 id="try-it-yourself">Try It Yourself</h3>
<p><a href="https://github.com/shawenyao/light">https://github.com/shawenyao/light</a></p>Fiat lux.Cat in Black2022-12-31T00:00:00+00:002022-12-31T00:00:00+00:00https://www.shawenyao.com/Cat-in-Black<p>They say time spent with cats is never wasted.</p>
<div align="center">
<img src="https://shawenyao.github.io/Photos/IMG_0584.jpg" />
</div>They say time spent with cats is never wasted.2022 FIFA World Cup Predictions2022-11-16T00:00:00+00:002022-11-16T00:00:00+00:00https://www.shawenyao.com/2022-FIFA-World-Cup-Predictions<p>Colley’s method strikes again.</p>
<p><img src="https://shawenyao.github.io/Who-is-number-1/main/2022/world_cup_2022.svg" alt="NBA Power Rankings - Colley's Method" /></p>Colley’s method strikes again.iPhone 7 Review&#58 6 Years Later2022-10-31T00:00:00+00:002022-10-31T00:00:00+00:00https://www.shawenyao.com/iPhone-7-Review-6-Years-Later<p>Reliving 2016.</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/iPhone 7/Portrait/IMG_0672.jpg" />
</p>
<blockquote>
<p>It’s the best iPhone that we have ever created. <br />
― Tim Cook, at the Apple Special Event on September 7, 2016</p>
</blockquote>
<p>I picked up an iPhone 7 Jet Black 128GB model for $749 plus tax on October 16, 2016 to replace my battery-swelling iPhone 5. As my daily driver of the next 6 years, it managed to do its job decently for the most part, serving as the primary access point to phone/video calls, social networks and the Internet in general, although the phone did begin to struggle toward its final days.</p>
<p>With the release of iOS 16 in September 2022, Apple officially dropped its support for the iPhone 7 series, concluding the lifecycle of the 2016 product - well, so did I. Today, I am taking one last look at the phone in my pocket for the longest time, revisiting its launch, design choices and 6-year service, as well as hints of its influence on the products that followed, before locking it away in the pantheon of digital history.</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/iPhone 7/Portrait/IMG_0670.jpg" width="49%" />
<img src="https://shawenyao.github.io/Photos/iPhone 7/Screenshots/home_screen.jpg" width="49%" />
</p>
<p><em>iPhone 7 running iOS 15.7 (home screen)</em></p>
<h2 id="launch">Launch</h2>
<p>On September 7, 2016, Tim Cook unveiled the iPhone 7 series at the Bill Graham Civic Auditorium in San Francisco. The next lineup in the iPhone family would include the regular iPhone 7 and the bigger iPhone 7 plus. Either model came equipped with an A10 Fusion chip that was, in Apple’s words, 40% faster than its predecessor A9 found in the iPhone 6s (2015) or iPhone 6s Plus (2015). Both of them also featured a 12-megapixel camera capable of optical image stabilization, something only available to the Plus model previously, but the 7 Plus model offered one additional 12-megapixel telephoto camera and portrait mode to create bokeh in photos. In addition, the iPhone 7 series introduced a haptic home button, stereo speakers, and a water-and-dust-resistant body, all for the first time on an iPhone.</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/iPhone 7/Screenshots/geekbench1.jpg" width="49%" />
</p>
<p><em>Geekbench score of the A10 Fusion chip (when battery is sufficiently charged)</em></p>
<h2 id="headphone-jack">Headphone Jack</h2>
<p>One of the biggest controversies surrounding the launch of iPhone 7 was its headphone jack, or the absence of one. Phil Schiller, Apple’s senior vice president of worldwide marketing, indeed sounded a little defensive when he took three whole minutes on stage characterizing it as a “courageous” move to challenge the long-established practice. Since then, Apple doubled down on the design with every subsequent iPhone release. The bet paid off. The Android camp fought back for a year or two before giving in eventually. Consumers have also learned to embrace the age of wireless audio, to the point where today, a headphone-jack-less phone has become all but the new default, at least among flagship smartphones on the market. History will remember that it all began with this phone.</p>
<table>
<thead>
<tr>
<th>Model</th>
<th>Year</th>
<th>Have a headphone jack?</th>
</tr>
</thead>
<tbody>
<tr>
<td>iPhone 14 Series</td>
<td>2022</td>
<td>No</td>
</tr>
<tr>
<td>Samsung Galaxy S22 Series</td>
<td>2022</td>
<td>No</td>
</tr>
<tr>
<td>Samsung Galaxy Z Flip 4 & Z Fold 4</td>
<td>2022</td>
<td>No</td>
</tr>
<tr>
<td>Google Pixel 7 Series</td>
<td>2022</td>
<td>No</td>
</tr>
<tr>
<td>OnePlus 10 Series</td>
<td>2022</td>
<td>No</td>
</tr>
<tr>
<td>Moto Edge+</td>
<td>2022</td>
<td>No</td>
</tr>
</tbody>
</table>
<p><em>An incomplete survey of major smartphones on the market in 2022</em></p>
<h2 id="home-button-and-touch-id">Home Button and Touch ID</h2>
<p>The removal of a headphone jack, according to Phil Schiller, freed up enough of the precious internal space in order to make room for another ingenious design: an immoveable yet clicky home button. Gone were the mechanical home buttons common to all iPhones prior, probably one of the most vulnerable parts of the hardware. The new, improved button was physically incapable of movement of any sorts, but the “taptic engine” inside would instead provide a subtle, vibrational feedback whenever the home button was pressed. The end result was an unmistakable impression of tactile “clicky-ness”. It just felt right.</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/iPhone 7/Screenshots/haptic.jpg" width="49%" />
</p>
<p><em>Configuration of the strength of the haptic feedback</em></p>
<p>Meanwhile, biometrics-based identification as a whole has only become more ubiquitous than ever six years later. The Touch ID technology that began with iPhone 5s (2015), along with its successor, Face ID introduced with iPhone X (2017), made it virtually impossible to go back to a time when the safety of data in your phone meant having to type a passcode each time it needed to be unlocked. Between the two though, I still have a slight preference for Touch ID, due to its versatility and the attention-free unlocking experience.</p>
<h2 id="camera">Camera</h2>
<p>iPhone 7 has a 12-megapixel camera, the pixel count of which was first introduced with the iPhone 6s series a year earlier and from there, remained unchanged until the iPhone 14 Pro line in 2022. Quality-wise, it’s what you can expect from an entry-level model of iPhone. It shoots sharp pictures with vibrant color under well-lit conditions. At night, the camera can still impress you with its optical image stabilization, but it might take a few attempts to get the perfect shot.</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/iPhone 7/IMG_6038.jpg" width="49%" />
<img src="https://shawenyao.github.io/Photos/iPhone 7/IMG_9145.jpg" width="49%" />
</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/iPhone 7/IMG_6477.jpg" width="49%" />
<img src="https://shawenyao.github.io/Photos/iPhone 7/IMG_5810.jpg" width="49%" />
</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/iPhone 7/IMG_7199.jpg" width="49%" />
<img src="https://shawenyao.github.io/Photos/iPhone 7/IMG_9121.jpg" width="49%" />
</p>
<h2 id="durability">Durability</h2>
<p>Battery is where the 6-year-old phone truly shows its weakness. In 2016, iPhone 7 was claimed to have longest battery life ever on an iPhone, which feels surreal today. In fact, the battery health has become so concerning that in the past year or so, I wouldn’t dare going outside without a power bank for an extended period of time. The worst part is that the phone seems to have lost its ability to gauge how much juice is left in the battery. Sometimes it can still go on for a few more hours with a terrifying “1%” in the top-right corner, reminding me of its age.</p>
<p>Shortly after iPhone 7’s launch, the battery of an iPhone would emerge at the center of a controversy dubbed “batterygate”. For years there had been anecdotal evidence suggesting that older models of iPhone became increasingly slower with each iOS upgrade, leading people to speculate that it was a conscious decision by Apple to encourage people to buy a new one prematurely, a practice known as “planned obsolescence”. The incident culminated with Apple’s apology in December 2017 in which the company promised to offer battery replacements at a reduced cost for a year and better transparency on battery and performance management in the future. Today, battery-induced performance throttling is still very much a thing. The phone performs about 40-50% slower when the system decides so, even without low battery mode kicking in.</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/iPhone 7/Screenshots/battery.jpg" width="49%" />
<img src="https://shawenyao.github.io/Photos/iPhone 7/Screenshots/geekbench2.jpg" width="49%" />
</p>
<p><em>Left: battery health after 6 years of degradation; right: Geekbench score of the A10 Fusion chip under CPU throttling conditions</em></p>
<p>Last but not least, about two years ago, the lightning port on my iPhone 7 lost its clutch power, resulting in a rather unstable connection between the cable and the body. This has led to more than a handful of frustrations when charging or driving, or charging while driving. It is not necessarily a problem worth fixing at this point. With USB-C iPhones heavily rumored, the lightning port might have finally run its course, following the footsteps of its predecessor, the 30-pin dock connector last seen on an iPhone 4s (2011).</p>
<h2 id="wrap-up">Wrap-up</h2>
<p>iPhone 7 was okay. The lack of headphone jack never became as big of a deal as many critics argued back then. The haptic engine made the home button the ultimate form of its former selves. The camera was sufficient for daily usage. Software support was average by iPhone’s standard (which means pretty good). It was neither as incremental as iPhone 8 (2017), nor as radical as iPhone X (2017). It was Apple doing what it does best - building a product and building it, in Steve Jobs’ words, at the intersection of technology and liberal arts.</p>
<p float="left" align="middle">
<img src="https://shawenyao.github.io/Photos/iPhone 7/Portrait/IMG_0669.jpg" width="49%" />
<img src="https://shawenyao.github.io/Photos/iPhone 7/Screenshots/lock_screen.jpg" width="49%" />
</p>
<p><em>iPhone 7 running iOS 15.7 (lock screen)</em></p>
<h2 id="references">References</h2>
<p>Wikipedia, “<a href="https://en.wikipedia.org/wiki/IPhone_7">iPhone 7</a>”</p>
<p>YouTube, “<a href="https://www.youtube.com/watch?v=NS0txu_Kzl8">Apple – September Event 2016</a>”</p>
<p>Engadget, “<a href="https://www.engadget.com/2016-09-13-iphone-7-and-7-plus-review.html">iPhone 7 and 7 Plus review: Apple (mostly) plays it safe</a>”</p>
<p>The Verge, “<a href="https://www.theverge.com/a/apple-iphone-7-review-vs-iphone-7-plus">iPhone 7 Review</a>”</p>
<p>The Verge, “<a href="https://www.theverge.com/circuitbreaker/2016/6/21/11991302/iphone-no-headphone-jack-user-hostile-stupid">Taking the headphone jack off phones is user-hostile and stupid</a>”</p>
<p>Wikipedia, “<a href="https://en.wikipedia.org/wiki/Batterygate">Batterygate</a>”</p>
<p>Wikipedia, “<a href="https://en.wikipedia.org/wiki/Planned_obsolescence">Planned obsolescence</a>”</p>
<p>The Verge, “<a href="https://www.theverge.com/2017/12/28/16827248/apple-iphone-battery-replacement-price-slow-down-apology">Apple apologizes for iPhone slowdown drama, will offer $29 battery replacements for a year</a>”</p>
<p>The Verge, “<a href="https://www.theverge.com/2022/10/26/23423977/iphone-usb-c-eu-law-joswiak-confirms-compliance-lightning">Apple confirms the iPhone is getting USB-C</a>”</p>Reliving 2016.Living in Canada2022-07-07T00:00:00+00:002022-07-07T00:00:00+00:00https://www.shawenyao.com/Living-in-Canada<p>An American perspective.</p>
<p>From 2019 to 2021, I had the pleasure of calling Toronto my home for two and a half years. During my stay, I began to come across various ways in which the Canadians behave differently from the Americans - many of them were frankly eye-opening in an amusing way.</p>
<p>Don’t get me wrong. For the most part, Canadians and Americans are <em>very</em> similar. Obviously, both of them speak English. Both like to talk about sports, celebrities and politics. Both are friendly and care about their community. By and large, they are all nice people.</p>
<p>But that’s not to say that the two are the same. Far from it. Probably the most visible difference between the two countries can be found in the system of measurement. Despite being a British Commonwealth nation, Canada uses the metric system as opposed to imperial. So instead of saying 60 miles per hour, you say 100 kilometers per hour. Instead of saying 70 Fahrenheit, you say 20 Celsius. And then there is the spelling. How do you spell “check” as in a checking account? In Canada, it is “cheque”.</p>
<p>Of course, there are also more subtle differences between two, and those are typically harder to notice. For example, one thing I realized after spending a few months there was that what the Americans call “401(k)” is known as “RRSP” in Canada, which stands for Registered Retirement Savings Plan, which, if you think about it, actually makes a whole lot of sense given how it is literally named after its sole purpose (as it should be), which begs the question of why the Americans are stuck with that unholy name, yet nobody seems to have a problem with it.</p>
<p>Speaking of financial services, one of the first things I decided to do after my arrival was to open a bank account. So, on my second day, I walked into a branch of TD Bank. An associate greeted me and offered to help.</p>
<p>“Good news,” she said. “We have reviewed your employment and income status, and we are glad to tell you that you are eligible for our Unlimited Chequing Account!”</p>
<p>“Thank you - this is great. Can you remind me what that ‘unlimited’ means?”</p>
<p>“Oh - it just means, you get to use your chequing account for an <em>unlimited</em> number of times each month at no additional cost.”</p>
<p>I managed to keep smiling, but deep down, that smile froze. Back in the states, an act of such immeasurable generosity happened to be the <em>only</em> kind of checking account I knew of. After all, what’s the point of putting your money in a bank if you cannot spend it whenever and however you like it? Well, later I learned that the bigger, more systematic issue behind all this was the fact that the Canadian banking system is even more centralized than its American counterpart, so the “Big Five” in Canada can get away with charging a premium for essentially the same services. That’s quite unfortunate for those who have been “spoiled” by the American banks.</p>
<p>Things are even worse for those who have been spoiled by the American shopping experience. For perspective, the city of San Francisco charges a sales tax of approximately 8.5% and most Americans will tell you how crazy and unaffordable that is. Meanwhile, the Ontario province demands 13% so the way they see San Francisco is more like, hey look, 5% off, <em>everything</em>. Not to mention the price differences because things are usually more expensive in Canada on a pre-tax basis already. The worst part of them all, and probably the number one reason why my mom would consider a peaceful Canadian life to be excruciatingly uneventful, has to be the promotions and the discounts, or rather, the lack thereof. While it isn’t uncommon for a U.S. retailer to slash a product’s sticker price by, say, 20% or more, especially during a big promotional week, deals of this kind are few and far between in Canada. Personally, I learned it the hard way.</p>
<p>It was Thanksgiving, 2020. The Covid lockdown had just been lifted. People reclaimed their freedom and oh boy were they ready for some holiday shopping. I walked into this Best Buy located in one of the most popular commercial districts in downtown Toronto. I did not have anything particular in mind to buy from my shopping list. I was simply there to share the excitement, see what was on the shelf and be delighted by the enormity of the bargains should I choose to patronize them. After months of not being able to walk in a physical store, I was <em>eager</em> to be impressed to say the very least.</p>
<p>And then, a giant poster hanging on the wall caught my eye. The moment I saw it, I came to the stunning realization that I most certainly would <em>never</em> be able to forget about what I just witnessed for the rest of my life. It was a piece of a beautifully designed ad, simple, elegant and straight to the point: “20% off all HDMI cables, with the purchase of any 4K TV.” Thank you very much.</p>An American perspective.