Air Quality Index Fitbit App Released

Anyware, LLC Fitbit app for the display of relevant air quality data for ozone and 10 & 2.5 micron particles has been approved and published on the Fitbit Gallery.

This app helps you to know the air quality in your area before exercising outdoors. The app displays the current air quality index (AQI) using the official U.S. AQI, a color-coded index designed to communicate whether air quality is healthy or unhealthy for you. Data are provided by AirNow, which is a one-stop source for all air quality data. Using your location provided by your phone, the app finds the nearest reporting station and displays the AQI for ozone and particles 10 & 2.5 microns or less. Touch on a reported value to see the value description as provided by the Environmental Protection Agency.

To use this app, you must register and create an account at AirNow. AirNow will provide you a unique API key that is entered under the app settings on your phone. Enter the API key as provided by AirNow including all dashes. This app uses this API key to get the most relevant reported AQIs using your phone’s GPS and network connection. Instructions for obtaining an API key and configuring the app are found here.

The app only works in the U.S. and some locations in Canada and Mexico. The user needs to be within 250 miles of a reporting station used by AirNow.

Fitbit SunRise SunSet App Issue [Resolved August 20, 2022]

This published Fitbit app utilizes an API provided by sunrise-sunset.org to get the sunrise and sunset times for a given date and location. As of August 9. 2022, the sunrise-sunset API https call has an invalid certificate creating an issue. Fortunately a user notified me of this problem. Since the API certificate is invalid, returned data is throwing an error that wasn’t being properly handled in the code [Note: sunrise-sunset.org updated their certificate allowing the API to respond properly].

I am currently working on an update to the companion code to handle the unexpected error, which is discussed below. Even with this error handling, if the sunrise-sunset.org API certificate is not resolved, this will required a change in how the sunrise and sunset times are obtained. Currently my plan is to publish an app update by October 1, 2022 [Note: An app update to handle malformed JSON responses was published August 24, 2022, Version 1.1.0].

This issue with the unexpected error is found in the companion app (the code that runs on the Fitbit app on your phone). In the Fitbit architecture, messages are passed between your watch and the companion app (see this Fitbit guide for more information). The companion app provides the gateway to the Internet. The API call uses fetch() with the api calling string. The response should be a JSON string, which is parsed and the data sent back to the watch for display.

The solution to handle the unexpected error is simple. I added a “catch” statement to handle the error and pass an error indicator back to the watch. The companion code segment is show below. This code waits for a message from the watch to get sunrise and sunset data. The companion app builds the api string and then makes the api call using fetch(). The JSON string components are extracted and sent back to the watch for display. The catch sends back-100 lat and lon to indicate an error has occurred.

// Listen for messages from the device
// Message has the date we need, companion has everything else
messaging.peerSocket.onmessage = function(evt) {
  if (evt.data) {
    console.log("evt.data " + JSON.stringify(evt.data));
    if (messaging.peerSocket.readyState === messaging.peerSocket.OPEN) {
      // build api string
      var apiString = "https://api.sunrise-sunset.org/json?lat=" + lat + "&lng=" + lng + "&date=" + evt.data.getDate;
      console.log(apiString);
      
      // go to the web to get sun rise/set data that is returned in a json string
      fetch(apiString)
        .then(function(response) {return response.json();})
        .then(function(json) {
        console.log("Got JSON response from server:" + JSON.stringify(json));
        
        messaging.peerSocket.send({
          getDate: evt.data.getDate, lat: lat, lng: lng, rise: json.results.sunrise, set: json.results.sunset});
      })
      .catch(function(err) {
        console.error('Error during fetch ' + err.code);
        messaging.peerSocket.send({
          getDate: evt.data.getDate, lat: -100, lng: -100, rise: 0, set: 0}); // network data error occurred
      });
    }
  }
}

When the watch receives a message with the error indicators, the watch displays that an error has occurred but continues to allow the user to change dates and try again.

Finding Unknown Resistor Value using Voltage

In the world of sensing, there are many sensors that change their resistance value based on the environment. Knowing the sensor resistance provides a measurement of the environment being measured. These variable resistor sensors include:

  • Thermistor – a variable resistor that changes value with the surrounding temperature changes. There are two types: negative temperature coefficient (NTC) and positive temperature coefficient (PTC). The NTC thermistor decreases in value when the temperature increases the the PTC thermistor increases in value when the temperature increases.
  • Magneto Resistor – a variable resistor that changes value when a magnetic field is applied. When the magnetic fields increases, the resistance increased. When the magnetic field decreases, the resistance decreases.
  • Photoresistor – a variable resistor that changes value based on light energy. The photoresistor resistance decreases when light energy is increased and increases when light energy is decreased.
  • Humistor – a variable resistor that changes value based on humidity.
  • Force Sensitive Resistor – a variable resistor that changes values based on the force that is applied.

Thermistors are variable resistors that are more sensitive to temperature changes then a standard circuit resistor. The simple first order thermistor relationship between resistance and temperature is:

ΔR = kΔT, where
ΔR is change in resistance (in ohms)
Δ is change in temperature (in kelvin)
k is first-order temperature coefficient (in ohms/kelvin)

In general the first order approximation is only accurate over a limited temperature range. The Steinhart-Hart equation is a widely used third order approximation that improves accuracy to less than 0.02 oC over a much wider temperature range.

where
T is absolute temperature (in kelvins)
R is the resistance (in ohms)
a, b, and c are coefficients

NTC thermistors can also be characterized with the Β (beta) parameter equation, which is just a specialized case of the Steinhart-Hart equation.

where
T is absolute temperature in kelvins
T0 is 298.15 K (25 oC)
R0 is resistance at T0
R is the resistance

Having the B parameter and measuring the thermistor resistance, the temperature can be determined. But most embedded systems don’t measure the resistance directly. So the question is how do we measure the thermistor resistance. The answer is to use a voltage divider. Measuring the voltage divider voltage, which is common using analog to digital converters, gives us a way to get the thermistor resistance.

Remember that a voltage divider is two series resistors in this case connecting power and ground. The voltage between the two resistors is given by:

NTC Thermistor Voltage Divider

VOUT = VIN x (R1 / (R1 + R2))
R2 = R1 x (VIN/VOUT – 1), where
R2 = unknown thermistor resistance (in ohms)
R1 = known resistance (in ohms)
VIN = known input voltage (in V)
VOUT = measured voltage between resistors (in V)

Generally NTC thermistors have a nominal resistance at 25oC. Most common is either 10K or 100K ohms. When picking the known resistor R1, the value should match the nominal thermistor resistance, e.g. for a 100K thermistor, R1 should be 100K.

Using an embedded controller like an Arduino UNO or Nano, the code is very simple to convert the sensed input voltage to the thermistor resistance, to a temperature as shown in following code segment.

  // in setup, one time calculation
  Rinf = NTCRESISTOR * exp(-1*BETA/298.15);


  // in Arduino loop
  tempIn = analogRead(TEMPPIN);  // 0 to 1023 values

  // find thermistor R
  // SERIESRESISTOR = R1, 1023.0 = VIN, tempIn = VOUT
  Rth = SERIESRESISTOR * ((1023.0/tempIn) - 1);
  // calculate temp in K and convert to C
  tempC = BETA/(log(Rth/Rinf)) - 273.15;

One final item to consider with a voltage divider is the input impedance of the measuring device. To limit the impact of input impedance on circuit performance, generally you want the input impedance to be at least 10 times the value of R1 in the circuit above. The input impedance is in parallel with R1 so if the input impedance is only 100K, then the effective value of R1 in our circuit is only 50K, which greatly affects the measurement and calculations.

Op Amp Voltage Follower

One way to solve this problem is to use a voltage follower op amp circuit. This circuit provides unity gain (voltage divider Vout equal op amp Vout), has a low output impedance, and very large input impedance. It is important to select an op amp that has stable unity gain.

Calculating Moon Phase

Recently I published a Fitbit app that calculates the Moon phase and then displays the proper phase image and illumination value. The user can select a different date or simply increment the date using buttons. Some feedback I received was that the app was fast and they wanted to understand why?

First, the app performs all calculations on the watch. No phone resources are need No GPS. No Internet. The calculations are based on a dateNow date object (this object is settable by the user though the interface that is not part of this discussion).

The calculation is based on an article I found by SubsySTEMs while performing an Internet search. Their paper broke the Moon phase calculation into a series of steps, which was easy to follow and translated directly to JavaScript. The output of their calculation is the number of days since the last New Moon. From there the Moon phase is determined. There are eight Moon phases (in order from New):

  • New
  • Waning Crescent
  • Third Quarter
  • Waning Gibbous
  • Full
  • Waxing Gibbous
  • First Quarter
  • Waxing Crescent

Using the days since the last New Moon you can find the phase but beware, each phase isn’t just 1/8 of 29.53 days. Shown below is the JavaScript that implements the attached paper.

function calMoonPhase() {
  // calculate moon phase for date
  let month = dateNow.getMonth() + 1;
  let year = dateNow.getFullYear();
  if(month < 3) {
    year = year - 1;
    month = month + 12;
  }

  let a = Math.floor(year/100);
  let b = Math.floor(a/4);
  let c = 2 - a + b;
  let d = dateNow.getDate();
  let e = Math.floor(365.25*(year+4716));
  let f = Math.floor(30.6001 * (month + 1));
  let jd = c + d + e + f - 1524.5;
  let daysSinceNew = jd - 2451549.5;
  let newMoons = daysSinceNew / 29.53;

  <...Determine Moon phase...>
  <...Determine image to show...>
  <...Calculate illumination...>


}

Sunrise/Sunset Fitbit App Released

Anyware, LLC Fitbit app for displaying the sunrise and sunset times were approved and published on the Fitbit Gallery.

The Sunrise/Sunset app displays the sunrise and sunset times for the users current location and time settings. The initial date displayed is the current date. The date display is a button that allows the user to select a different date for the sunrise and sunset data or the user can push the increment button to advance to the next date. This app uses the phone’s GPS and network connection to obtain the sunrise and sunset data. No user data is saved and only the user’s current location is transmitted to an API provided by Sunrise-Sunset.org.

Fitbit Apps Published

Anyware, LLC Fitbit apps for Poker Hand ranks and Moon Phases were approved and published on the Fitbit Gallery.

Poker Hand app is designed as a simple player reminder of poker hand ranks while sitting at the table. The app is a simple scrolling list that displays poker hand ranks from highest to lowest. This app uses no user data.

The moon phases app displays the current moon phase and illumination percentage for the given date. The initial date displayed is the current date. The date display is a button that allows the user to select a different date for the moon phase, or the user can push the increment button to advance to the next date. This app uses no external resources and no user data is saved or transmitted.

The Node Method

In the next update to my book, AC/DC Principles and Applications, I plan to add a small section on the Node Method to Chapter Nine – Complex Network Analysis Techniques. Discussed in this chapter are Kirchoff’s voltage and current laws, superposition, Thevenin’s and Norton’s theorems. This post is an advance installment of the update.

The Node Method is a circuit analysis approach that uses the circuit element properties with Kirchoff’s voltage and current laws. This method helps to reduce analysis complexity as seen in the example.

Each element connection point is a circuit node. In using the Node Method, each node voltage is label with one node being selected as ground or 0 volts. Each node also has the current labeled showing the currents entering and leaving each node.

After all the node voltages and currents are labeled, KCL is written for each node. Based on Ohm’s Law, the current through a resistor is the voltage across the resistor divided by the resistance. The voltage across a resistor is the voltage difference between the terminals.

Using the set of KCL equations, solve for the missing information.

Node Method Steps

  1. Select a reference node to be 0 volts (ground). A good choice for this reference node is one that has the most connections.
  2. Label voltages and currents.
  3. Write KCL equations for each node that has an unknown voltage.
  4. Solve for missing values using the equations developed in step 3.

Example

Using Figure 9-3, what is the voltage drop for a 2Ω load resistor that is connected between a 12V closed-loop circuit (loop A) with a resistance of 4Ω and a 6V closed-loop circuit (loop B) with a resistance of 3Ω?

Write KCL
IL = I1 + I2
e/2Ω = (12V – e)/4Ω + (6V – e)/3Ω

Solve for node voltage e
6e/12Ω = 3(12V – e)/12Ω + 4(6V – e)/12Ω
6e/12Ω = (60V – 7e)/12Ω
13e/12Ω = 60V/12Ω
e = 60V/13
e = 4.6V
IL = 4.6V/2Ω
IL = 2.3A

This solution was simpler than creating the KVL for each loop, solving for I1, I2, and then IL, and then finding the node voltage e.