IQ symbol when rounding the temperature

On a watchface I have created, some users are getting the IQ Symbol error on their watches when they show the current tmperature.  I recently added a line of code to round the number for the temperature because on some watches it shows to several decimal places.  Since adding the line other users have started getting the error.  Does anyone know what might be going on?  I can't recreate the fail on my watch or on the simulator.

Here is the config for the most recent user with issues: Forerunner 965. Firmware version 18.12

The code to pull the weather is below:

                        var currentConditions = "--";
                        if (Toybox.System.getDeviceSettings() has : phoneConnected){
                            if (Weather.getCurrentConditions() != null) {
                                currentConditions = Weather.getCurrentConditions().temperature;
                                if (currentConditions != null) {
                                    currentConditions = currentConditions * 9/5 + 32;
                                    currentConditions = currentConditions.toNumber(); // THIS IS THE LINE OF CODE CAUSING THE ISSUE
                                    currentConditions = currentConditions + StringUtil.utf8ArrayToString([194,176]);
                                } else {
                                    currentConditions = "--";
                                }
                            } else {
                                currentConditions = "--";
                            }
                        }
Thanks,
Will
  • Not sure why your code is crashing but you should change your code which converts from Celsius to Fahrenheit.

    According to the API docs, Weather.CurrentConditions.temperature is a Number, which means that "/5" in "currentConditions * 9/5 + 32" will do integer division, not float division as intended. (In order to do float division, one of the operands has to be a float.)

    For example.

    var x = 1;
    var y = x * 9/5;
    System.println("1 * 9/5 = " + y);
    y = x * 9.0/5;
    System.println("1 * 9.0/5 = " + y);

    Output:

    1 * 9/5 = 1
    1 * 9.0/5 = 1.800000

    Also, regardless of your crashing issue, Math.round(currentConditions ).toNumber() would be more correct instead of currentConditions.toNumber(). Math.round() rounds to the nearest integer, while toNumber() truncates.

    e.g.

    System.println("(1.8).toNumber() = " + ((1.8).toNumber()));
    System.println("Math.round(1.8) = " + Math.round(1.8));
    System.println("Math.round(1.8).toNumber() = " + Math.round(1.8).toNumber());

    Output:

    (1.8).toNumber() = 1
    Math.round(1.8) = 2.000000
    Math.round(1.8).toNumber() = 2

  • When you access things in Weather.getCurrentConditions(), you always want to null check things you are trying to use.  Based on time and specific data, it's not uncommon.  The one where I see a null most often is "feelsLikeTemperature"

    If you look in the API doc, everything is typed like this:

    feelsLikeTemperature as Lang.Number or Null

     

    typed like this, with null being a valid return, and doing math on "null" or a toNumber() on null will cause the error you see,

    Do null checks.

    It looks like you do this in your code, so this was for others reading this.

    What is the error you see in the ciq_log file?

  • Current conditions is already a number and it doesn’t make sense to have toNumber() function on a Number. Likely those devices don’t support that function on the Number type.

  • To apply all of that to your actual code, I would replace the following lines…

    currentConditions = currentConditions * 9/5 + 32;
    currentConditions = currentConditions.toNumber();

    …with

    currentConditions = Math.round(currentConditions * 9.0 / 5 + 32).toNumber();

     

    Note that I purposely changed the spacing from "currentConditions * 9/5 + 32" to "currentConditions * 9.0 / 5 + 32", because the former seems to imply that 9/5 will be evaluated first, then multiplied by currentConditions, which is not the case (multiplication and division are evaluated left to right.)

    Having said all of that, it's still not clear to me why your code is crashing. However, if it's really because some devices don't support x.toNumber() where x is a Number, that should solve your problem, since the result of the new calculation will be a Float and Math.round() will also return a Float.

    Current conditions is already a number and it doesn’t make sense to have toNumber() function on a Number. Likely those devices don’t support that function on the Number type.

    Whether it makes sense or not, toNumber() as an instance method of Number has existed since CIQ 1.0.0, so if some devices are really crashing due to code that calls toNumber() on an instance of Number, I would consider that a device bug.

    As a counter-example, in javascript, every object type supports toString(), even including String objects. Same goes for Java. Keeping that in mind, I don't see why it's so crazy for every Numeric (Number/Float/Long/Double) type in Monkey C to support toNumber().

  • I recently added a line of code to round the number for the temperature because on some watches it shows to several decimal places.

    Wanted to mention this before, but this suggests that, contrary to the documentation, Weather.CurrentConditions,temperature isn't a Number on every device. Given the following code:

    currentConditions = Weather.getCurrentConditions().temperature;
    if (currentConditions != null) {
         currentConditions = currentConditions * 9/5 + 32;

    If you print out currentConditions and it displays with more than 0 decimal places, that suggests that Weather.getCurrentConditions().temperature and the result of the calculation ([Weather.getCurrentConditions().temperature] * 9/5 + 32) are both Floats/Doubles.

    If Weather.CurrentConditions.temperature is a Number, then the calculation as given will result in a Number, which should print without decimal places. (Because, as mentioned above, the result of multiplying or dividing a Number by a Number is always a Number)

    However, if Weather.CurrentConditions.temperature is sometimes a Float/Double, then the result of the calculation will also be a Float/Double. Multiplying or dividing 2 numbers, where at least 1 number is a Float/Double, results in a Float/Double.

    This still doesn't explain why your code is crashing, unless as Ultra mentioned, some devices don't support calling toNumber() on a Number (which again, would be a bug in CIQ.)

  • maybe it's the next line?

    currentConditions = currentConditions + StringUtil.utf8ArrayToString([194,176]);

    Why are you adding a string to some numeric? I know, I know, I did the same mistake in a couple of places in my apps, but this doesn't always work in Monkey C as we think (from other languages). Try:

    currentConditions = "" + currentConditions + StringUtil.utf8ArrayToString([194,176]);

    BTW: why don't you replace StringUtil.utf8ArrayToString([194,176]) with a string constant?