Magnetometer API Privacy Concerns

Many Android phones have an integrated magnetometer available to native apps. Chrome browser for Android also makes that capability available to web apps, but right now it is hidden by default as a feature preview. Once I enabled that feature, I was able to follow some sample code online and quickly obtain access to magnetometer data in my own web app. That was so easy! Why was it blocked by default?

Apparently, the answer (or at least a part of it) was that it was too easy. Making magnetometer and other hardware sensor data freely available to web apps would feed into hardware-based browser fingerprinting. Even though magnetometer data by itself might be innocuous, it could be combined with other seemingly-innocent data to uniquely identify users thereby piercing privacy protections. This is bad, and purportedly why Apple has so far declined to support sensor APIs.

That article was in 2020, though, and the web moves fast. When I read up on magnetometer API on MDN (Mozilla Developer Network) I encountered an entire section on obtaining user permission to read hardware sensor data. Since I didn’t have to do any of that for my own test app to obtain magnetometer data, I guess this requirement is only present in Mozilla’s own Firefox browser. Or perhaps it was merely a proposal hoping to satisfy Apple’s official objection to supporting sensor API.

I found no mention of Mozilla’s permission management framework in the official magnetometer API specification. There’s a “Security and Privacy Considerations” section but it’s pretty thin and I don’t see how it would address fingerprinting concerns. For what it’s worth, “limiting maximum sample frequency” was listed as a potential mitigation, and Chrome 111 only allows up to 10Hz.

Today users like myself have to explicitly activate this experimental feature. And at the top of “chrome://flags” page where we do so, there’s an explicit warning that enabling experimental features could compromise privacy. In theory, people opting-in to magnetometer today is aware of potential abuse, but that risk has to be addressed before it’s rolled out to everyone.

Magnetometer API in Android Chrome Browser

I became curious about magnetometers and was deep into shopping for a prototype breakout board when I remembered I already had some on hand. The bad news is that they’re buried inside mobile devices, the good news is that they’re already connected to all the supporting circuitry they need. Accessing them is then “merely” a software task.

Android app developers can access magnetometer values via position sensor APIs. It’s possible to query everything from raw uncalibrated values to device orientation information computed from calibrated magnetometer data fused with other sensor data. Apple iOS app developers have the Core Motion library from which they can obtain similar information.

But I prefer not to develop a native mobile app because of all the overhead involved. For Android, I would have to install Android Studio (a multi-gigabyte download) and put my device into Developer Mode which hampers its ability to run certain security-focused tasks. For iOS I would have to install Xcode, which is at least as big of a hassle, and I’m not sure what I’d have to do on an iOS device. (Installing TestFlight is part of the picture, but I don’t know the whole picture.)

Looking for an alternative: What if I could access sensor data from something with lower overhead, like a small web app? Checking on the ever-omniscient, I found that a magnetometer API does exist. However, it is not (yet?) standardized and hidden behind an optional flag that the user has to explicitly enable. I typed chrome://flags into my address bar and found the “Generic Sensor Extra Classes” option to switch from “Default” to “Enable”. After making this change, the associated magnetometer test turned from red to green.

One annoyance of working with magnetometer on Android is that I have to work against an actual device. While Chrome developer tools has an area for injecting sensor data into web apps under test, it does not (yet?) include ability to emulate magnetometer data. And looking over Android Studio documentation, I found settings to emulate sensors like an accelerometer but no mention of magnetometer either.

Looking online for some sample code, I found small code snippets in Google Chrome Developer’s blog about the Sensor API. Lots of useful reference on that page but I wanted a complete web app to look at. I found what I was looking for in a “Sensor Info” web app published from Intel’s GitHub account. (This was a surprising source, pretty far from Intel’s main moneymaker of CPUs. What is their interest in this field? Sadly, that corporate strategic answer is not to be found in this app. I choose to be happy that it exists.) Launching the app, clicking “+” allowed me to add the magnetometer sensor and start seeing data stream through. After looking through this Intel web app’s source code repository, I wrote my own minimalist test app streaming magnetometer data. Success! I’m glad it was this easy, but perhaps that was too easy?

Source code for this exploratory project is publicly available on GitHub

Magnetometer Quick Look

Learning about Hall effect switches & sensors led to curiosity about more detailed detection of magnetic fields. It’s always neat to visualize something we could not see with our eyes. Hall sensors detect magnetic field along a single axis at a single point in space. What if we can expand beyond those limits to see more? Enter magnetometers.

I thank our cell phones for high volume magnetometer production, as a desire for better on-device mapping led to magnetometer integration: sensitive magnetometers can detect our planet’s magnetic field to act as a digital compass to better show a map on our phones. Since a phone is not always laid flat, these are usually three-axis magnetometers that give us a direction as well as magnitude for the detected magnetic field.

But that’s still limited to a single point in space. What if we want to see the field across an area, or a volume? I started dreaming of a project where I build a large array of magnetometers and plot their readings, but I quickly bogged down in details that made it clear I would lose interest and abandon such a project before I could bring it to completion.

Fortunately, other people have played with this idea as well. My friend Emily pointed me to Ted Yapo’s “3D Magnetic Field Scanner” project which mounted a magnetometer to a 3D printer’s print head carriage. Issuing G-code motion commands to the 3D printer control board, this allowed precise positioning of the sensor within accessible print volume of the 3D printer. The results can then be plotted out for a magnetic field visualization. This is a great idea, and it only needs a single sensor! The downside is that such a scheme only works for magnetic fields that stay still while the magnetometer is moved all around it. I wouldn’t be able to measure, say, the fields generated by an electric motor’s coils as it is running. But it is still a fun and more easily accessible way to see the magnetic world.

I started window shopping magnetometer breakout boards from Adafruit, who has an entire section in their store dedicated to such devices. Product #5579 is built around the MMC5603 chip, whose sensitivity is designed for reading the Earth’s magnetic field. For non-compass scenarios, such sensitivity would quickly become saturated near a magnet. Adafruit recommended product #4366 built around the TLV493D chip for use with strong magnets.

I thought it would be interesting to connect one of these sensors to an ESP8266 and display its results on a phone web interface, the way I did for the AS7341 spectral color sensor. I was almost an hour into this line of thought before I realized I was being silly: why buy a magnetometer to connect to an ESP8266 to serve its readings over HTTP to display in a phone browser interface? My Android phone has a magnetometer in it already.

Hall Effect Sensors Quick Look

Learning about brushless direct current (BLDC) motors, I keep coming across Hall-effect sensors in different contexts. It was one of the things in common between a pair of cooling fans: one from a computer and another from a refrigerator.

Many systems with BLDC motors can run “sensorless” without a Hall sensor but I hadn’t known how that was possible. I’ve learned they depend on an electromagnetic effect (“back EMF”) that only comes into play once the motor is turning. To start from a stop, sensorless BLDC motors depend on an open-loop control system “running blind”. But if the motor behaves differently from what that open-loop control expected, startup sequence fails. This explains the problem that got me interested in BLDC control! From that, I conclude a sensor of some sort is required for reliable BLDC motor startup when motor parameters are unknown and/or the motor is under unpredictable physical load.

Time to finally sit down an learn more about Hall effect sensors! As usual I start with Wikipedia for general background, then moving on to product listings and datasheets. Most of what I’ve found can be more accurately called Hall effect switches. They report a digital (on/off) response to their designed magnetic parameters. Some of them look for magnetic north, some look for magnetic south, others look for a change in magnetic field rather than a specific value. Some are designed to pick up weak fields of distant magnets, others are designed for close contact with a rare earth magnet’s strong field. Sensors designed to detect things like a laptop lid closing don’t need to be fast, but sensors designed for machinery (like inside a brushless motor!) need high response rates. All of these potential parameters multiply out to hundreds or thousands of different product listings on an electronic component supplier website like Digi-Key.

With a bit of general background, I dug up a pair of small Hall effect sensor breakout boards (*) in my collection of parts. The actual sensor has “44E” printed on it, from there I found datasheets telling me it is a digital switch that grounds the output pin when it sees one pole of a magnet. If it sees the other pole, or if there is no magnet in range at all, the output pin is left floating. Which pole? Um… good question. Either I’m misunderstanding the nomenclature, someone made a mistake in one of these conflicting datasheets, or maybe manufacturers of “44E” Hall switches aren’t consistent in which pole triggers pulling down the output pin.

Fortunately, the answer doesn’t matter for me right now. This breakout board was intended for use with microcontrollers like Arduino projects, and it also has an onboard LED to indicate its output status. This is good enough for me to start. I connected the 5V to center pin, ground to pin labeled “-“, and left the “S” pin unconnected. The onboard LED illuminated when I held it up against one pole. When held up against the opposite pole, or when there’s no magnet nearby, the LED stays dark.

I also knew there was a Hall sensor integrated into an ESP32. This one is not just an on/off switch, it can be connected to one of ESP32’s ADC channels to return an analog value. Sounds interesting! But ESP32 forums report the sensor is only marginally useful on the type of ESP32 development board I use. The ESP32 chip itself is packed tightly alongside other chips, under a metal RF shield, resulting in a very noisy magnetic environment.

Looking more into similar standalone sensors, I learned some keywords. To get more data about a nearby magnet, I might want an “analog” sensor that detects a range of values instead of on/off relative to some threshold. Preferably the detected output value changes in “linear” response to magnetic field, and to tell the difference between either pole or no magnet at all I’d want a “bipolar” sensor. Searching on Digi-Key for these parameters and sorted by lowest cost found the TI DRV5053: analog bipolar hall effect sensors with linear output. Available in six different levels of sensitivity and two different packages. And of course, there are other companies offering similar products with their own product lines.

They might be fun to play with, but they only detect magnet field strength at a single point along a single axis. What if I wanted to detect magnetic fields along more than one axis? That thought led me to magnetometers.

(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.

Brushless Motors with Two(?) Phases

During teardowns, I usually keep any motors I come across, even if I have no idea how I’d use them. Recently I got a pair of hard drive motors spinning again, a good step forward in my quest to better understand brushless direct current (BLDC) motors. I’ve also learned enough to spot some differences between motors. Those that I’ve successfully spun up are three-phase motors, with three sets of coils energized 120 degrees out of phase with each other to turn the rotor. But not all of the motors I’ve disassembled fit this description.

There’s a class of motors with only two sets of coils. Based on what I know of three-phase brushless motors, that would imply two sets of coils are 180 degrees out of phase. A naive implementation would have no control over which direction the rotor would spin, but I’ve found these in cooling fans, where the direction of spin is critical, so there must be more to this story. (If it doesn’t matter which direction the motor spins, we only need a single coil.)

What I’ve observed so far is that a Hall-effect sensor is an important part of this mystery, because I looked up this control chip found inside a computer cooling fan and read it had an integrated Hall sensor.

A Hall sensor is also part of this refrigerator evaporator fan motor control circuit.

Searching online for an explanation of how these motors worked, I found this thread “How do single phase BLDC motors start in proper direction?” on Electronics StackExchange. I don’t fully understand the explanation yet, but I do understand these motors aren’t as symmetric as they look. A slight asymmetry allows enforcing the correct turn direction. The hall sensor adds a bit of cost, but I guess it is cheaper than additional coils.

Even better, that thread included a link to Electric Drive Fundamentals on Electropaedia. This page gives an overview of fundamental electromagnetic principles that underpin all electric motors. I knew some of these, but not all of them, and certainly not enough to work through the mathematical formulas. But I hope studying this page will help me better understand the motors I find as I take things apart.

Independent of building an understanding of electromagnetic fundamentals, I also want to better understand Hall sensors critical to running certain motors.

Two Hard Drive Motors on BLHeli_S Controller

I bought some brushless motor controllers meant for multirotor aircraft: A four-pack intended for quadcoptor drones. But instead of running a motor turning a propeller, I started with a small motor salvaged from a laptop optical drive. (CD or DVD I no longer remember.) It spun up with gusto, and I watched the motor control signals under an oscilloscope. That was interesting, and I shall continue these experiments with more of my teardown detritus: computer hard drive motors.

2.5″ Laptop Hard Drive

This hard drive was the performance bottleneck in a Windows 8 era tablet/laptop convertible. The computer was barely usable with modern software until this drive was replaced with an SSD. Once taken out of use, I took it apart to see all the intricate mechanical engineering necessary to pack hard drive mechanicals into 5mm of thickness. The detail important today are these three pads on the back, where its original control board made electrical contact with the spindle motor.

They are now an ideal place for soldering some wires.

This motor is roughly the same size as CD/DVD motor. But because I never figured out how to remove the hard drive platter, there is significantly more inertia. This probably contributed to the inconsistent startup behavior I saw. Sometimes the drone motor controller could not spin up the motor, it would just twitch a few times and give up. I have to drop PWM control signal back down to zero throttle and try again. Something (maybe the platter inertia, maybe something else) is outside the target zone of the drive controller’s spin-up sequence. This has been a recurring issue and my motivation to learn more about brushless motors.

Side note: This motor seemed to have a curious affinity for the “correct” orientation. I had thought brushless motors didn’t care much which direction they spun, but when I spun the platter by hand (without power) it would coast for several seconds in the correct orientation but stop almost immediately if I spun it backwards. There’s a chance this is just my wrist, applying more power in one direction versus another, or there might be something else. It might be fun to sit down and get scientific about this later.

3.5″ Desktop Hard Drive

I then switched out the 2.5″ laptop hard drive motor for a 3.5″ desktop computer hard drive motor. This isn’t the WD800 I took apart recently, but another desktop drive I took apart even further back.

I dug it out of my pile because it already had wires soldered to the motor from a previous experiment trying to use the motor as a generator. The data storage platters had been removed from this hard drive so I expected less problems here, but I was wrong. It was actually more finicky on startup and, even if it starts up, never spins up very fast. If I try turning up the speed control signal beyond a certain (relatively slow) point, the coil energizing sequence falls out of sync with the rotor which jerkily comes to a halt.

I was surprised at that observation, because this motor is closest size-wise to the brushless outrunner motors I’ve seen driving propellers. There must be one or more important differences between this 3.5″ hard drive motor and motors used for multirotor aircraft. I’m adding this to a list of observations I hope I can come back to measure and articulate those important differences. Lots to learn still, but at least I know enough now to notice something’s very different with brushless motors built from even fewer wires and coils.

CD/DVD Motor on BLHeli_S Controller Under Oscilloscope

I dug up a brushless motor salvaged from a laptop optical drive and wired it up so I could connect it to a cheap brushless motor controller running BLHeli_S firmware. This firmware supports multiple control protocols, but I’ll be sending classic RC servo control pulses generated by an ESP32 I had programmed to be a simple servo tester.

I saw what looked like a WS2812-style RGB LED on the motor controller circuit board and was disappointed when I didn’t see it light up at all. I had expected to see different colors indicating operating status. Instead, the firmware communicates status by pulsing the motor coils to create a buzzing tone. I found an explanation of these beeps on this Drones StackExchange thread titled “When I power up my flight controller and ESC’s, I hear a series of beeps. What do all of the beeps mean?” The answer says the normal sequence is:

  • Powered-Up: A set of three short tones, each higher pitch than the previous.
  • Throttle signal detected (arming sequence start): One longer low pitch tone.
  • Zero throttle detected (arming sequence end): One longer high pitch tone.

(The author of that answer claimed this information came from BLHeli_S manual, but the current edition I read had no such information I could find. Was it removed? If so, why?)

Once the “arming sequence end” tone ends, I could increase my throttle PWM setting to spin up the little motor. It spins up quite enthusiastically! It responded exactly as expected, speeding up and slowing down in response to change in motor control PWM signal.

Oscilloscope Time

Once I verified the setup worked, I added my oscilloscope probes to the mix. I wanted to see what the motor power waveforms looked like, and how it compares against what I saw from an old Western Digital hard drive.

That might be a bit jumbled, so here are the phases separately. We can see they are in a sequence, one after another. They all peak at battery power level, and there’s a transition period between peaks. The transitions don’t look as smooth as the Western Digital controller and I don’t have a center wye tap to compare voltage levels against.

Next experiment: try the same controller with different motors.

Prepare Salvaged CD/DVD Motor for Test

Using a brushed DC motors is easy: apply voltage, watch motor shaft turn. I’m exploring brushless DC motors and even the cheapest controller from Amazon had features that I hadn’t even known existed. It is far more sophisticated than a DC motor driver (DRV8833) I explored earlier. To make it actually turn a motor, I’ll start simple with the smallest brushless motor I found in my pile of salvaged hardware.

This is a small brushless motor in the spindle of a CD or DVD drive. Based on the fact it is only a few millimeters thick, it was probably salvaged from a laptop optical drive. Lots of wires visible in the pale-yellow ribbon cable. I will need to probe them looking for a set of three or four wires, with a tiny bit of resistance between them, that would indicate coils for the brushless motor.

I probed the set of four contacts closest to the motor, but found no electrical connection between them.

This set of four wires looked promising. They ended abruptly, as if I had cut them off from a larger piece of pale yellow flexible printed circuit. (FPC) I guess the rest of that circuit didn’t look interesting to keep and what they were have been lost to history. I used sandpaper to uncover the copper traces within this cut-off segment. This work was for naught: no electrical connections here either.

This left the large connector of many wires. I noticed the five conductors in the middle are wider than the rest. Each of those led to two contact points on the connector. I started with those and found likely candidates in three of the five wide wires. I’m not sure what the other two were… perhaps power and ground for some other circuit? Whatever they were, I hope they aren’t relevant to my current experiment.

I soldered thin (30 gauge *) wires to each of those points. Using an old AA battery as ~1V source, energizing any two of these wires would result in the motor holding a position. Motor coils confirmed!

A bit of careful cutting and heat-shrink tubing isolated these wires from each other.

Resulting in a motor that I can connect to my brushless motor controller running BLHeli_S firmware.

(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.

BLHeli_S Brushless Motor Control Firmware and DShot Protocol

For curiosity and learning, I wanted to poke at a commercial brushless motor controller. Thanks to the current popularity of multirotor aircraft, the cheapest option on Amazon that day was a four-pack designed for small quadcoptor drones. Among the listing description is a string “BLHeli_S” that meant nothing to me at the time. Once I received the product and looked it over, I saw “BLHeli_S” written on the label as well, I thought I should at least do a web search to learn more.

BLHeli_S is a development of BLHeli motor control firmware, whose source code is on GitHub. From what I can understand, BLHeli_S is a port to SiLabs 16-bit microcontrollers offering higher performance than original BLHeli 8-bit hardware target. At first, I was thrilled there might be another brushless motor algorithm I could try to learn from, but my enthusiasm quickly cooled when I realized BLHeli_S was written in assembly language for maximum performance. That’s hard core. Understanding that codebase might take more work than I’m willing to put in.

I found additional information on Ardupilot website, which supports BLHeli_S and the even newer BLHeli32 motor controller firmware. In addition to standard RC servo control signal, these controllers also support a more advanced protocol called DShot. It allows higher bandwidth and lower latency, as well as digital checksum to detect and discard corrupted control signals. The most fascinating feature is bidirectional communication, which allows the motor controller to send back information like motor RPM. BLHeli_S also supports OneShot and OneShot125 protocols, but they offer neither the wide compatibility of RC servo style PWM nor the advanced features of DShot. I’m probably never going to touch those.

I could find scattered reviews of BLHeli_S like this one. The most interesting page I stumbled cross was What is DShot ESC Protocol which pointed me to Betaflight. Skimming through Betaflight’s GitHub repository, I found its DShot command driver. It was much easier than trying to find Ardupilot’s implementation. (This is as close as I got.)

Looking for implementations outside of those large flight controller projects, I found several GitHub repositories of people taking a stab at it.

I also found an Arduino forum thread of someone asking about bidirectional DShot protocol, and the answer was a link to DShot – the missing Handbook. I doubt I would learn SiLabs assembly to dig into BLHeli firmware itself, but it might be interesting to talk to my new BLHeli_S brushless controllers via bidirectional DShot.

For my first experiment, though, I’m going with the tried-and-true RC servo PWM.

Brushless Motor Controller for Multirotor Aircraft

I want to learn how to control brushless motors and how to best tailor their control algorithms to different tasks. Most brushless motors I encounter are very tightly coupled to their associated controller. Occasionally I could examine how a particular pairing worked together, but I don’t know enough to mix and match salvaged motors/controllers to see how different combinations work together. I think I should start with a motor controller that has been designed to accommodate a range of different brushless motors.

The good news: recent popularity of multirotor aircraft (“drones”, “quadcoptors”, etc.) has spawned a product ecosystem of brushless motors and controllers marketed to drone owners. Whether they want to repair, upgrade, or build their own from scratch, many companies compete for their money. I just wanted something cheap as a starting point, so I went with Amazon’s lowest bidder of the day(*) for a four-pack of compact and lightweight brushless motor controllers. Obviously intended to match four motors in a quadcoptor, a pack of four works for me in the interest of redundancy. I may damage a few in my experiments.

Here’s one of the four, just removed from its packaging. I was impressed by its tiny size, the circuit board itself is only about 13mm x 23mm. Thicker red and black wires are for delivering battery power. The thinner wires led to 0.1″ pitch connectors for control signal and signal ground. There are no wires provided for the motor, just three solderable tabs.

I cut away its protective heat-shrink tubing to see inside. On the upper-left I see “S” for white control signal and “-” for signal ground. Probing with my meter indicates signal ground is connected to power ground. This isn’t usually a problem because drones tend to run everything off a single battery but would exclude this controller from circuits isolating logic ground from power ground.

In the center we see two microchips. Larger chip on the right has a logo I don’t recognize, and text SA6288 210. A web search found this SA6288, a gate driver chip designed to drive MOSFET/IGBT transistors to control power for three-phase motors. That fits. It’s probably taking orders from the other chip, then. A microcontroller makes sense given its proximity to the control input signal and four circular pads across the bottom that may be a way to reprogram the chip. I read its markings to be “dB21 F16C C01Q5K 2217”. Search engines clung on to “F16C” and wanted to tell me about the fighter jet, which wasn’t helpful. Maybe I’ve misread one or more characters.

Backside of the chip are all of the power control components, starting with red wire (VBAT) and black wire (GND) for battery power. Relatively large capacitors are visible, and I’m impressed it didn’t need larger electrolytic capacitors. Half of this side are taken up by an array of six modules. From my LX-16A teardown I recognize the logo for Alpha & Omega Semiconductors, but their website didn’t have any information on a 7544 chip. Arrow Electronics says there’s should be an AON7544 N-Channel “AlphaMOS” MOSFET. Two of them per channel would fit with my current understanding of brushless motors.

One of the remaining two chips should be a voltage converter to translate battery power to a lower voltage for the unidentified microcontroller and gate driver chip. But on the lower left, next to the ground wire, is an unexpected entity. It looks like a WS2812 or similar RGB LED module which is much fancier than the single LED I would have expected for an indicator light.

There’s a mysterious name “BLHeli_S” on the Amazon listing and also printed on the front label of this motor controller. A web search found this to be the name of motor control firmware.

(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.

Potential Brushless DC Motor (BLDC) Starting Points

Learning more about brushless DC motor control have been on my to-do list for several years, ever since I learned of another maker’s problems with motor control algorithms that did not suit the task. I’m still not ready to dive into this field yet, but I thought I’ve collected enough potential sources of information that it’s worth writing them down.


When I looked at ESP32, one of the features that caught my eye was its motor control pulse-width modulation (MCPWM) peripheral. I used it for my Micro Sawppy rover project which used it to control DC gearmotors in each of the rover’s six wheels. But it is also applicable for controlling two brushless DC motors. Espressif’s ESP32 BLDC control example project looked interesting. Putting it to work directly without modification requires a motor with integrated hall sensor and additional hardware (MOSFETs and gate drivers) I don’t have at the moment. I’ve noticed that MCPWM seems to be missing from more recent Espress microcontrollers, does this mean customer demand hasn’t been high enough to justify continued development? If so, that’s a shame but also a warning I might not want to get too invested in a feature of uncertain future.


For something more fully-featured than an Espressif demo, I could look at SimpleFOC. It’s a library for Arduino framework that supports many microcontrollers with Arduino cores. Ranging from the original ATMega328P to STM32 to ESP32. (ESP32 port claims to use its MCPWM peripheral.) This is promising, but SimpleFOC documentation seems to be aimed at people who already knew a lot about brushless motors and know what they want. I need to do more studying before I can absorb information within.

There are a few “reference implementations” for power circuits controlled by SimpleFOC software, but it looks like most of them are out of stock due to the global semiconductor shortage. There are also projects that build on SimpleFOC like this custom wheeled robot controller featured on Hackaday.


Another open-source project for brushless motor control is VESC. Its documentation is even more opaque to me than SimpleFOC was. (One of them could be built on top of the other for all I know.) What I got out of VESC site is that its primary focus are on brushless motors of sizes suitable for carrying a person around: electric skateboards, scooters, etc.

Theory of Operation

Looking online for beginner-level introductions, I first found How to Make Advanced BLDC Motor Controllers which, despite the name, stayed quite beginner-friendly and did not get very advanced. Here I learned terminology like “trapezoidal drive” which is easier to implement than “sinusoidal drive” which is what field-oriented controllers like SimpleFOC and VESC does. I also learned of dangers like “shot-through condition” which risks short-circuiting and blowing out our controller circuit and/or our power supply.

Another beginner-friendly article is How to Power and Control Brushless DC Motors. This is the second time I got a beginner’s primer from Digi-Key’s Article Library. The previous lesson involved USB power delivery. And with these two successes, I think I should look around that library to find more educational resources. It didn’t take long before I found Controlling Sensorless, BLDC Motors via Back EMF.

Of course, this study syllabus is only important because I want to understand what’s going on behind the scenes. If I just want to spin a motor, the easiest thing to do is to buy a commercial controller. Which I’ve also done to see what I can learn.

Hello ESPAsyncWebServer

I have several interesting sensors in my hardware to-do pile, and I think it’d be interesting to do a series of interactive UIs one for each sensor. My first effort in this vein was a browser UI to interactively play with an AS7341 spectral color sensor, and I learned a lot doing it.

One lesson was that I could perform all sensor data computation and visualization in the browser, so I don’t need much in the way of microcontroller capabilities. The ESP32 I used for AS7341 web UI was overkill. All I needed was an I2C bus and WiFi, so I could easily drop down to an ESP8266. However, because I had used the WebServer from ESP32 Arduino Core library, I will need an ESP8266-friendly replacement.

Sticking with Original Repository

I decided to look into ESPAsyncWebServer, which I had been using indirectly as a dependency of ESPHome. In addition to supporting ESP8266 as well as ESP32, it had a few other features I liked. The most important being its ability to serve files from flash file system, so I don’t have to do silly things like hexadecimal encoding files to program memory. Using this capability also means switching from Arduino IDE to PlatformIO, because the latter has easy tools to work with flash file system. And finally, I was intrigued by the claim ESPAsyncWebServer can serve GZip-compressed files. Making better use of our precious megabyte of flash memory.

The only worry is that the GitHub repository looks stale. There are over 100 open issues, and there are 69 pull requests sitting unmerged. Maybe I should use one of the forks that saw more recent development? Since I was introduced via ESPHome, I thought I would try their fork of the repository. It has seen more recent work, but unfortunately as of this writing, the most recent merge has a C syntax error.

.pio\libdeps\d1_mini\ESPAsyncWebServer-esphome\src\AsyncWebSocket.cpp: In function 'size_t webSocketSendFrame(AsyncClient*, bool, uint8_t, bool, uint8_t*, size_t)':
.pio\libdeps\d1_mini\ESPAsyncWebServer-esphome\src\AsyncWebSocket.cpp:105:23: error: expected primary-expression before ')' token
  105 |   if (!client->send();) return 0;
      |                       ^

It’s been sitting broken for over a month now. I don’t know the story behind the scenes, but it is clear the repository is in no shape to be used. I don’t know which of the other forks might be worth investigating. As an introduction, I’ll start with the original until I run into a compelling reason to do otherwise.

SPIFFS vs. LittleFS

There were a few examples to help me orient myself with ESPAsyncWebServer. Compiling them myself, though, brought up warnings that SPIFFS is now deprecated and I should switch to LittleFS. This was opened as an issue #780 against ESPAsyncWebServer library, but was closed without further action because the warning came from an optional SPIFFS-specific component called SPIFFSEditor. Since it is optional and not relevant to my projects, I can choose to ignore the warning.

Switching over is a little tricky because we build the code and file system separately, and they are two different uploads. If I upload the file system first, it gets reformatted by the code when it sees a file system it doesn’t recognize. As per documentation: “attempting to mount a SPIFFS volume under LittleFS may result in a format operation and definitely will not preserve any files, and vice-versa” In order to end up with a functional system, I need upload code using LittleFS then upload LittleFS file system contents.

Gzip Compressed Files

After verifying a simple “Hello World” web server worked, I compressed the small index.html into index.html.gz. Uploading the new LittleFS system, I was happy to see it come up in my browser! But how does this work? I queried using curl and found the answer:

HTTP/1.1 200 OK
Content-Length: 1284
Content-Type: text/html
Content-Encoding: gzip
Content-Disposition: inline; filename="index.html"
Connection: close
Accept-Ranges: none

ESPAsyncWebServer added “Content-Encoding: gzip” to the HTTP header effectively making the browser deal with it. As the browser will be running on a far more powerful CPU than the ESP8266, it is indeed better suited to handle decompression.

Serve Angular Web Application

As a test of compression, I brought over my Angular tutorial app “Tour of Heroes”. It’s not as simple as just copying the files, though. As per Angular deployment guide, I needed to add a rule so ESPAsyncWebServer will serve up index.html rather than a 404 error when an URL is not found.

  server.onNotFound([](AsyncWebServerRequest *request){
    request->send(LittleFS, "/www/index.html");

Another problem was that LittleFS has a 31-character name limit. (32 characters + null termination.) Unfortunately, my Angular app bundle had a file polyfills.716cc9a230a87077.js.gz which is 32 letters! The hexadecimal hash was generated by “–output-hashing” option of “ng build”. It’s changed on every build in order to avoid using stale cached versions of polyfills.js. I could skip that feature, but then I run the risk of stale cached files. The other workaround is to skip compressing polyfills.js. Dropping the “.gz” extension resulted in a 29-letter filename that works for LittleFS.

With all files in my Angular app compressed (except for polyfills.716cc9a230a87077.js) the size of the app dropped from ~800kB down to ~230kB. This is a dramatic difference when default available flash storage is only 1MB out of a total of 4MB total flash memory onboard.

Should I use Angular to build my ESP8266-hosted sensor web UI projects? No. It is far too heavyweight and a simple sensor UI does not need the capabilities of Angular application framework.

Will I use Angular to build my ESP8266-hosted sensor web UI projects? Possibly. Angular is not the best tool for the job, but it might be valuable for me to practice Angular by starting with something simple.

Source code for this exploratory project is publicly available on GitHub

More Non-Photorealistic Rendering

Today’s post is an appreciation for the continued evolution of computer animation using non-photorealistic rendering. The previous post has more details and words, today is more about the embedded YouTube videos.

I first learned about this technique from Disney’s animated short Paperman. (Watch on Disney+.)

Which evolved to Feast, another Disney animated short. (Watch on Disney+)

For behind-the-scenes reasons I don’t know, this technique hasn’t made it to a Disney theatrical release. Concept art were released for Bolt and Tangled showing they had ambitions to adopt this visual style, but both of those final products were rendered in a photorealistic style. We can see bits and pieces of the ambition left in those film, though, in bits of art visible in the background.

Whatever the reason, it left the door open for Sony Pictures to take the lead with Spider-Man: Into the Spider-Verse.

Members of that team followed up with The Mitchells vs. The Machines. (Watch on Netflix.)

Thankfully those were great films in their own right, independent of their novel visual style. I enjoyed them very much and their success opened the door (or more accurately, loosened studio wallets) for more and I am looking forward to them. Not all of them will be great films, nor would they necessarily succeed in pushing the state of the art, but I’m glad to see it happen.

The Bad Guys might be fun. Plot-wise, it doesn’t feel fresh after Wreck-It Ralph. In terms of visual style, it is the least adventurous relative to its contemporaries. Perhaps the technology team at DreamWorks/Universal Studios needed to keep things manageable for their first run.

If so, then I’m thankful that film paved the way. Puss in Boots: The Last Wish has a much more distinct visual style, and this trailer is hilarious. It had its theatrical run recently so I should be able to access a home video digital rental or purchase soon.

And now Paramount Pictures is trying it out as well, as seen in the recently released trailer for Teenage Mutant Ninja Turtles: Mutant Mayhem. I love this art style, especially how it is so distinct from the others on this list. (I don’t know my art terminology… “rougher” or “sketchier” doesn’t seem to quite cut it.) This trailer is a lot of laughs and I hope the visual style pair well with another reboot of the TMNT franchise.

Outside of films, there are shows like Arcane (on Netflix)

This will show up in more places, in more formats, in the years ahead. It looks like there’s already too much for me to see them all myself, which honestly is a fantastic problem to have.

Angular “Tour of Heroes” Unit Tests For 100% Code Coverage

After learning all the ways an Angular web app can perform HTTP communication, I have a better understanding more of Angular’s “Tour of Heroes” tutorial app. And even better, I have a better idea of how I could write unit tests for it! That wasn’t something covered by the tutorial itself, so writing tests for the tutorial app is my self-assigned extracurricular activity. This follows my previous self-assigned homework, an aesthetic overhaul using Angular Material component library.

An Angular project created via “ng new” command sets up a unit testing pipeline and a few boilerplate tests. “Tour of Heroes” was created this way but it was never touched in the tutorial. Every time we call “ng create” to add a component, that boilerplate also added a simple test to verify that component could be created in the test framework. By the end of the tutorial, we have a handful of these simple creation tests. Most of which would fail, because those components have become more complex than the original boilerplate and the test hasn’t been updated to match.

Import Dependencies

First step was to import all the missing dependencies so a component can even be created in the test harness. I first did this mostly by searching for error messages and copying the answers, but it was an unsatisfying approach because I didn’t understand what I was doing. To address this, I paused my mindless copy/paste and started studying. I started with Angular Developer Guide to Testing which led to my reactive programming tangent with RxJS. Now I’m back, and I understand how to use import section of TestBed.configureTestingModule to bring in dependencies needed by component under test.

HttpClientModule to HttpClientTestingModule

Once components could be created, I was faced with a long list of HTTP failures. They all had the same cause: components that need to perform HTTP communication imported HttpClientModule, which tried to make actual HTTP calls to a server that isn’t online. For unit tests, we need to use HttpClientTestingModule to redirect component HTTP activity to behavior controlled by unit test infrastructure.

Mock Services and overrideComponent

Once tests were in place for services that used HTTP directly, errors came from components that indirectly used HTTP via those services. To keep tests small (the whole point of unit tests) I stubbed out those services with mockups that had just enough behavior to support specific unit tests and no more. Hooking them into the system required using overrideComponent to switch out real services for their simpler mockups.

For my first pass, I wrote mockups directly as TypeScript classes. This is a simpler and more direct first pass, but I think I’m supposed to use “Spy” mechanism provided by Jasmine testing framework for such mockups. Learning to use Spy is still on the to-do list.

Code Coverage Report

Running “ng test –code-coverage” activates code coverage report courtesy of Istanbul. A brief coverage summary is printed to console every time the test suite is executed, but I wanted more details to see where I need to focus my effort. The detailed report is in HTML format under the /coverage/ subdirectory. I’m supposed to go double-click on that file to bring it up in a web browser, but I’m running Angular inside a VSCode Dev Container and I can’t “just” go and double-click that file as it is not accessible to my local web browser.

Solution: quickly whip up a static file web server with the serve-static package, letting my local web browser access the report via a port opened on my dev container. I added that file along with a shortcut to my packages.json file so I can bring it up by running “npm run coverage.”

100% Is Not 100%

=============================== Coverage summary ===============================
Statements   : 100% ( 82/82 )
Branches     : 100% ( 7/7 )
Functions    : 100% ( 47/47 )
Lines        : 100% ( 75/75 )

These mechanisms helped me to write unit tests that exercised all code paths: 100% code coverage! But this metric is misleading, because there’s much more to an Angular app than its TypeScript code.

Many important pieces of functionality live within HTML templates and are not covered by code coverage statistics. That requires accessing ComponentFixture.nativeElement. From there we can navigate the DOM tree, query for elements, and verify they are expected.

There’s much more to Angular testing. I haven’t even gotten into other things like verifying Angular router functionality but I am getting tired of Tour of Heroes. Time for a change of pace.

Notes on Angular “HTTP Client” Guide

A working understanding of reactive programming with RxJS Observables for Angular was listed as a prerequisite to Angular guide for HTTP client. After my long and convoluted tangent to learn RxJS, I felt I was finally ready to dive in and learn how to apply RxJS to handle HTTP transactions in an Angular web application.

One of the most powerful aspects of RxJS is the declaration of an Observable pipeline is a template. It means we can set one up independently of using them. To use them we call subscribe(), and it is a template that we can reuse by calling subscribe() again. An unexpected downside of this power is that nothing actually happens until we call subscribe(), which can be counterintuitive when we use the Angular HTTP client for operations like DELETE. Outside of Angular/RxJS, such things are fire-and-forget but here we have to subscribe() to start things in motion even if we don’t really care about the results of that subscription. This is apparently a common mistake because it is called out multiple times on this page. I also remember seeing this in the “Tour of Heroes” tutorial, which was absolutely wild when I first saw it. I now understand why it behaves that way, but I still think it is weird.

Unrelated to RxJS, I thought “Requesting a typed response” section was interesting. It enables TypeScript compile-time checking, which helps keep our code straight, but we have to remember we’re still on the hook for runtime checking. Sanitizing data is important for security! This also explains why the example code would copy elements from the result and not blindly copy the whole object. Blind copy would leave our code vulnerable to a maliciously written object that comes with its own toString() or something that is likely to get called in the context (and authority!) of our application code.

With my current basic understanding of RxJS and HTTP, the first half of this page was fairly straightforward. Then things got weird with “interceptors”. I understand it is a very powerful concept that allows separation of concerns across different chunks of code, each handling an aspect of HTTP activity. But getting them to all play nicely together seems to be a challenging task with lots of room for error. A very powerful gun aimed at our feet, it seems.

Even just loading them up has pitfalls. There’s a recommendation to load them with a “barrel” but I haven’t understood the tradeoffs to use/not use them. I also understood that load order mattered, but it didn’t cover symptoms of getting the order wrong. There’s even a back channel for application code to control interceptors (passing metadata) via HttpContextToken object.

An application of interceptor that looked very impressive was the ability to return a cached value immediately while also issuing the HTTP request. Then the real updated live value from the server is given, all on the same Observable! This is something that would have been really complicated to do with plain JavaScript Promise (async/await) and the first real “A-ha” for me to see power of RxJS in action.

Interceptors are also how Angular performs client-side work to protect against cross-site request forgery (XSRF) adding an XSRF-TOKEN in the header. It’s only part of the solution, though. It needs to mesh with server-side code to set the token and verify the token. It is on my “To-Do” list to find an implementation example, probably with Express.

And finally, there’s a section on using HTTP client in unit tests. This is the section I can put to work immediately.

Notes on Angular “Observables & RxJS” Guide

I went on a reactive programming tangent thinking it would help me become an effective user of Angular web application framework. Because some very important parts of Angular made extensive use of a JavaScript reactive programming library called RxJS. I found a lot of general information about reactive programming out there, but I need to stay focused on Angular. Returning to Angular documentation, I picked another developer guide section to start reading: “HTTP client“. This page has a “Prerequisites” section at the top which linked to an “Observables & RxJS Guide“.

It was an introduction to reactive programming with the RxJS library, with examples that are relevant to Angular apps. I didn’t know this guide existed. If I had, I would have started here first! If I had, I still wouldn’t have understood RxJS immediately, but I would at least have a better focus as I ventured to other RxJS guides. Mostly thanks to Observables in Angular which showed the most common RxJS usage patterns.

I was mildly disappointed the Practical Usage page had only two examples, and one of them was the type-ahead autocomplete mechanism already covered in Tour of Heroes. At least that one had a breakdown of how the asynchronous processing pipeline worked to accomplish its goal. The other example “Exponential backoff” had no such explanation. Just an overly optimistic claim “With observables, it is very easy” before we were tossed a chunk of code with no comments nor a breakdown of what it did. Definitely room for improvement here.

RxJS Observables were compared & contrasted against JavaScript Promises in the “Observables compared to other techniques” section. I saw some unavoidable overlap with similar topics on other resources I recently read but still, it was a great way to help my brain think about how to make use of RxJS aligned with its strengths. But I know the best way to get comfortable with RxJS is to start working on code that use it.

Notes on ReactiveX

I have fallen down a reactive programming rabbit hole. This all started because I wanted to learn modern web app development. There are many frameworks to choose from, and I decided to start with Angular. Web development is an inherently asynchronous endeavor, and one of the major tools in Angular’s toolbox for managing asynchronous data flow is a library called RxJS. Official RxJS documentation was quite unfriendly to beginners, so I looked around and found a website called “Learn RxJS” which turned out to be an extended pitch for a paid course. I’m not upset at the author for that, I’m just not ready to spend that kind of money. For curiosity’s sake, I looked at the author’s Twitter stream and felt like I stumbled into a clubhouse where everyone in the clique is into something I don’t understand.

Seeing a larger world around reactive programming made me realize RxJS isn’t a JavaScript library floating in isolation, it is an implementation of an idea bigger than a web framework (Angular) or even a programming language (JavaScript). I was one click away from this fact ever since I started looking at RxJS, but I didn’t notice. Its source code repository is at Meaning it is a project of an organization called ReactiveX. Looking at their list of repositories under shows multiple projects with the Rx prefix, each corresponding to a language (RxJava) or a platform (RxAndroid) From there I found the ReactiveX website at

In hindsight it made sense why information on was so terse and assumed the reader already knew the basics. That site was mainly focused on JavaScript specific issues, not general concepts and overview. General background and introduction information would only overlap with content on ReactiveX. Which, by the way, seems to have a Java-centric voice. I inferred RxJava was the first ReactiveX project and RxJS came sometime afterwards.

Reading ReactiveX Introduction page, I felt it is much better written for beginner friendliness. Or maybe it’s just the fact I’ve been reading similar words written by different people enough times for ideas to finally sink in. And while I feel I better understand goals of this project, I wouldn’t call myself a convert of the faith. I’ve seen enough shiny new toys to immediately spot some potential problems. For example, one part of the introduction tells us reactive programming meant we can focus on abstract concepts and its implementation details would not matter.

Screen snip excerpt of ReactiveX introduction claiming independence from implementation details.

That may be true in perfect theory land, but I’ve seen this claim before. I know it falls over as soon as I have to debug a problem. At which point implementation details matter quite a lot! When something crashes in the middle of the library, and I have no idea how my code relates to the crash stack I see in the debugger, it’s gonna be a long day.

I will admit reactive programming is an intriguing concept and, as I saw earlier, some people behind the Angular framework are pushing for Angular to become more reactive. To their credit, reactive programming is a concept that has outlasted some lesser flash-in-the-pan ideas. Looking at Wikipedia, ReactiveX has been kicking around for over a decade. However, reactive programming is still early on its road to maturity. That particular Wikipedia page was marked with “This article has multiple issues” as did the page on reactive programming in general.

For my immediate future, I believe I understand it well enough to stumble through its usage in Angular web application framework. It’ll be a long time before I can become a skilled craftsman at RxJS, but at least I would no longer become bewildered when I see code using it. This is good enough for me to get back to learning Angular.

Notes on “Learn RxJS”

As part of learning web application development platform Angular, I’m trying to get a grip on a software library called RxJS. It is a part of Angular framework for purposes related to asynchronous data processing but I don’t understand it enough to recognize when it might be the right tool for a job. RxJS official documentation was seriously lacking in beginner-approachable information. But if it is important enough to be a part of Angular, I assumed it would have its fans online. I looked around to see if anyone has published a tutorial and the first example I found was “Learn RxJS” by Brian Troncone.

This site has a page titled “RxJS Primer” which is a far more effective introduction than anything I found on RxJS official documentation. It is followed by “Get started transforming streams with map, pluck, and mapTo” which walks through a two parallel examples: one using standard JavaScript Array’s map method and another using RxJS counterpart map method. This was a good look at how RxJS allows developer to think about asynchronous event processing in a way similar to processing elements in an array. I’m not quite that familiar with, though, so I was sort of learning about both at the same time. Which, to the author’s credit, they had accounted for.

After reading those pages, I clicked around the site hoping for more content of similar quality. Unfortunately, I think those two pages were the free trial teaser for the author’s paid RxJS instruction courses. I don’t begrudge the author for making a living from their knowledge, but I’m yet not at a point where it makes sense for me to spend $129 on it.

If I’m willing to learn on my own from small snippets of sample code, there is a section on the site for that. “Recipes” is a list of small JavaScript webapps that focus on showing how we can use RxJS to accomplish various tasks. Everything from an input textbox autocomplete type-ahead (which is what “Tour of Heroes” used RxJS for) to a minimalist implementation of Tetris. Majority of these recipes were implemented with absolutely minimal amount of HTML & CSS and a few lines of very terse JavaScript full of RxJS. I appreciate the minimalism because that helps me focus on the core, but reading RxJS is like reading a foreign language I barely understand. In an ideal world, abstract code would be accompanied by plain-English code comments, but comments are conspicuously absent from these examples.

Clicking author Brian Troncone’s Twitter handle @BTroncone, the most recent (non-pinned) retweet was about something new in Angular called Signals. Following links, I saw “Angular Reactivity with Signals“, a design/planning/thinking document that I only partially understood. What is clear to me is that some of the people behind Angular are pushing to increase this “reactivity” concept beyond using RxJS in Angular, so it must be bigger than just a single JavaScript library.

Tiny Step on RxJS Learning Curve

I learned a lot from reading Angular’s Developer Guide to Testing, one of which is that I have a significant weak spot in my Angular understanding: how and when to use RxJS for asynchronous operations. Not just for testing, but also for writing Angular application code. On my first run through “Tour of Heroes” tutorial, RxJS was a black box I didn’t understand at all. On my second run, I understood the tutorial enough to understand specific uses of RxJS from context, but my understanding did not extend to the rest of that library. I certainly don’t know how to employ RxJS for my own tasks. It’s time to buckle down and read official RxJS documentation.

This was quite a chore. It appears RxJS official documentation was written by its development team for an audience that already knows what it does and why they would want it. It started with “RxJS is a library for composing asynchronous and event-based programs by using observable sequences” and jargon gets thicker from there. (Interspersed with words like “just” and “simply” which this beginner found ridiculous.) There was no “Getting Started” section. The next-best candidate section “Installation” is full of material telling existing users how to migrate breaking changes, not an introduction to new users.

The good news is that, as of this writing, RxJS is still under active development. Today’s stable release 7.8.0 has a timestamp only a few weeks old. (December 15th, 2022.) I was concerned about that, because RxJS was a solution for JavaScript asynchronous programming before JavaScript evolved to have its own asynchronous constructs like async/await. It doesn’t map cleanly to Promises and conversion is a bit of a mess. But RxJS still does things that standard JavaScript doesn’t do, so there are still scenarios where RxJS would be the right tool for the job. It’ll take more learning before I recognize those scenarios.

Observable: RxJS foundation class. One thing that demystified a lot was rewriting an analogy using plain JavaScript. Seeing something familiar and understandable (with my very recent JavaScript education) gave me a starting point to try understanding the rest of the page. Unhelpfully this was at the bottom of the page.

Observer: It took a while for me to understand observer where my code fits into the system and I can use as little or as much of it as I need for a scenario. It can be a single callback for receiving data (“next”) but I can also register optional callbacks to be notified of problems (“error”) or when there’s no more data (“complete”).

Operator: Documentation said this is the powerful part of RxJS, but didn’t really explain why or how we would leverage that power. This is also where marble diagrams were explained, something that bewildered me when Angular testing discussed marble testing. The overview of available operators is a disappointing list of just names. Each name is a link to their reference page without any additional context. I’d have to click the link and read each one. I would love a reference where each link has an 1-2 sentence summary, but no luck here.

Subject: These are Observable that multicasts to more than one Observer. Up until this point I hadn’t known a basic Observable only broadcast to a single Observer! This critical information should have been covered earlier.

Scheduler: No usage examples or scenarios were given so I have no idea when I should care about choosing a different RxJS scheduler. I see the “How to do X”, but not “Why you want to do X.”

I’m sure everything in official RxJS documentation is technically correct but the information lacks context. Or more precisely, I don’t think they were even trying to provide context for readers who are unaware. Perhaps there are resources to help RxJS beginners elsewhere on the internet?

Notes on Angular Developer Guide to Testing

Once my Angular development container could run tests in Chrome using headless mode, I could see actual test failures. Since “Tour of Heroes” tutorial did not touch test files at all, these failing tests were untouched boilerplate tests. For the most part they just test to see if a component instance could be created within the test harness, there were no further updates to test “Tour of Heroes” functionality. Components that couldn’t be created in a test harness obviously led to abysmal code coverage numbers.

=============================== Coverage summary ===============================
Statements   : 18.75% ( 15/80 )
Branches     : 0% ( 0/8 )
Functions    : 6.38% ( 3/47 )
Lines        : 16.21% ( 12/74 )

Since I am just getting started, there were a lot of (1) copy error message (2) search on that message (3) read hits on StackOverflow (4) repeat. Component creation failure mainly revolved around fixing up “imports” or declarations” sections to calling TestBed.configureTestingModule(). After I got component startup sorted out, code coverage numbers looked a lot better.

=============================== Coverage summary ===============================
Statements   : 61.25% ( 49/80 )
Branches     : 0% ( 0/8 )
Functions    : 53.19% ( 25/47 )
Lines        : 62.16% ( 46/74 )

But that was a lot of copy/pasting from StackOverflow with little understanding of what happened. And even though tests registered as passing, there were still error messages shown on console output. I need to learn more, so I started reading the “Testing” section of Angular Developer guides. It seems to assume I know Jasmine and Karma, which I don’t. I plan to skim the first pass for a partial understanding, then maybe dedicate some time to learning Jasmine/Karma, then come back again. Here are some notes from my first pass:

Valuable Live Examples

Just like the “Understanding Angular” section, pages in “Developer Guides” very frequently have a link to a project that we can load up and examine either by downloading code for our own machine or fire it up within our browser connected to a StackBlitz virtual machine. Having functional code is always great and mitigates many documentation issues. One code snippet in “Testing Services” documentation called a function I couldn’t find any information about, looking at the live code I figured out it was something strictly within the demo project. (async-observable-helpers.ts)

Scattered Older Content

I see occasional signs of outdated content. Some examples: (1) API TestBed.get() was deprecated from Angular 9 but still pops up here and there. (2) Occasional mentions of “Tour of Heroes” that doesn’t match the tutorial I just completed a second time. Either they were snippets from an older version of the tutorial, or the example was modified for illustration purposes. (3) Standard boilerplate code listed in “Basics of Testing Components” do not match what today’s tools generate.

Having illustrative code examples fall out of date reminded us to keep in mind that some of their associated information might be out of date as well.

Component Testing Scenarios

The longest page (by far) in this section is “Component Testing Scenarios.” I think it is the goldmine. A list of how we might want to test our Angular components and tools to go about them. It puts a lot of Angular testing tools (which have their own section) in context of problems they were created to solve. As a beginner I don’t quite understand why I might want to do these things, but here’s the reference if I want to do them.

Almost a quarter of this very long page is dedicated to “Component with async service”. (Which makes this one section longer than most other pages in “Angular Developer Guides – Testing”) RxJS is used by Angular a lot in the realm of asynchronous behavior, so I need to learn more about that. Not just to test, but to build Angular in general. I expect things will make sense after getting a better grasp of RxJS terminology like “marble testing“. I thought the best place to start would be RxJS official documentation. (I was wrong.)