Complete
over 4 years ago

Not a bug.

Weather.getCurrentConditions().attribute crashes when data is not available SDK 3.2.1

I am using the brand new shiny SDK 3.2.1 weather feature which I absolutely love. However, I was dismayed when my watch face crashed in the simulator after I unchecked the "Weather Data Available" box in the settings. I was calling Weather.getCurrentConditions().temperature, and I got an unexpected type value error. When I called Weather.getCurrentConditions() instead, it recognized it as a null value and I could use an if statement to work around it. I have not tested the other weather functions or attributes.

Can the attributes for the weather functions get null values when data is not available? Thanks

Former Member
Former Member
Parents
  • The documentation for Weather.getCurrentConditions() explicitly says that it may return null if no data is available. The API is behaving as advertised, the issue is with your code.

    This is your code from line 211:

    if (Weather.getCurrentConditions().temperature == null) {
    

    The problem is that Weather.getCurrentConditions() can return null. If it does, your code evaluates to this...

    if (null.temperature == null) {
    

    The null value doesn't have any member data (no temperature field), so you can expect that to produce an error, which it does.

    If you want to do this correctly (and efficiently), you want to check for null in places where it is possible and avoid multiple calls to getCurrentConditions. Something like this:

    var currentConditions = Weather.getCurrentConditions();
    if (currentConditions != null) {
        // current weather conditions are available
        // it is safe to access the temperature field
    
        var currentTemperature = currentConditions.temperature;
        if (currentTemperature != null) {
            // we have a valid temperature in `currentTemperature`
            mCurrentTemperature = currentTemperature.toString();
        } else {
            // no temperature data
            mCurrentTemperature = "--";
        }
    } else {
      // no current weather conditions
      mCurrentTemperature = "-";
    }

    If you're targeting only devices with 3.2.0 support, you don't need to do the has check mentioned by . If you are going to support older devices, you must take care to never access the Weather module without checking that it exists with a has check.

    class MyWatchFaceView extends WatchUi.WatchFace
    {
        var mHasWeather;
        var mTimer;
    
        function initialize() {
            WatchFace.initialize();
    
            mHasWeather = (Toybox has :Weather);
        }
        
        function onShow() {
            var millisecondsPerMinute = 60 * 1000;
            var weatherUpdateIntervalMinutes = 75;
            mTimer = new Timer.Timer(self.method(:onTimer), weatherUpdateIntervalMinutes * millisecondsPerMinute, true);
        }
        
        hidden var mCurrentTemperature;
        
        function onTimer() {
        
            if (mHasWeather) {
                // use the code above in here to set mCurrentTemperature
                // to a string based on weather and temperature availability
            }
        }
        
        function onUpdate(dc) {
            // ...
    
            if (mCurrentTemperature != null) {
                dc.drawText(x, y, font, mCurrentTemperature, justify);
            } else {
                // onTimer has not executed yet, so we don't have a temp
            }
        }
    }

Comment
  • The documentation for Weather.getCurrentConditions() explicitly says that it may return null if no data is available. The API is behaving as advertised, the issue is with your code.

    This is your code from line 211:

    if (Weather.getCurrentConditions().temperature == null) {
    

    The problem is that Weather.getCurrentConditions() can return null. If it does, your code evaluates to this...

    if (null.temperature == null) {
    

    The null value doesn't have any member data (no temperature field), so you can expect that to produce an error, which it does.

    If you want to do this correctly (and efficiently), you want to check for null in places where it is possible and avoid multiple calls to getCurrentConditions. Something like this:

    var currentConditions = Weather.getCurrentConditions();
    if (currentConditions != null) {
        // current weather conditions are available
        // it is safe to access the temperature field
    
        var currentTemperature = currentConditions.temperature;
        if (currentTemperature != null) {
            // we have a valid temperature in `currentTemperature`
            mCurrentTemperature = currentTemperature.toString();
        } else {
            // no temperature data
            mCurrentTemperature = "--";
        }
    } else {
      // no current weather conditions
      mCurrentTemperature = "-";
    }

    If you're targeting only devices with 3.2.0 support, you don't need to do the has check mentioned by . If you are going to support older devices, you must take care to never access the Weather module without checking that it exists with a has check.

    class MyWatchFaceView extends WatchUi.WatchFace
    {
        var mHasWeather;
        var mTimer;
    
        function initialize() {
            WatchFace.initialize();
    
            mHasWeather = (Toybox has :Weather);
        }
        
        function onShow() {
            var millisecondsPerMinute = 60 * 1000;
            var weatherUpdateIntervalMinutes = 75;
            mTimer = new Timer.Timer(self.method(:onTimer), weatherUpdateIntervalMinutes * millisecondsPerMinute, true);
        }
        
        hidden var mCurrentTemperature;
        
        function onTimer() {
        
            if (mHasWeather) {
                // use the code above in here to set mCurrentTemperature
                // to a string based on weather and temperature availability
            }
        }
        
        function onUpdate(dc) {
            // ...
    
            if (mCurrentTemperature != null) {
                dc.drawText(x, y, font, mCurrentTemperature, justify);
            } else {
                // onTimer has not executed yet, so we don't have a temp
            }
        }
    }

Children
  • Not all devices with 3.2 have Weather (the f5+ for example).  

  • Dear Jim, may I please ask? I see in ERA that users of my watch have the same error with weather, because I did not implement the check for Weather module. How is this possible, if I set in manifest that Minimum SDK version is 3.2.x, then all users should have watch firmware compatible with 3.2.x and therefore should have Weather module. As for hardware, I am supporting only Fenix 6X and Tactix Delta. So is it possible that someone can install the Watch face and may not have proper support for Weather module on his watch? Or could there by any other cause that weather is not populated into variables?

  • Not all of the 3.0 devices have 3.2 and some didn't get 3.1 (like the Oregon).  In the sim, it's only a few, like the va4, va4s, va3m and venu, but some devices just got 3.2 like the fr945 with the 5.00 FW that rolled out last week.

  • Former Member
    Former Member over 4 years ago in reply to Former Member

    Actually, I just saw the list of device compatibility on the Developer page. The version compatibility is listed as 1.0, 2.0, 3.0. I assume all devices listed under 3.0 are compatible with 3.2.0?

  • Former Member
    Former Member over 4 years ago in reply to Travis.ConnectIQ

    Thanks Travis and Jim! This is very helpful. It makes sense that null.attribute would return an error. When I first saw all the features in the weather module I was impressed. You guys are doing a great job. Some significant improvements indeed.

    Question -- How do I know whether a device has 3.2.0 support without running the has check?