Weather / simulator

Hi to the support, I just saw that you add a “weather” device simulator. That’s great but it would be fantastic if I could change it for my town…
I had already put a post on it but I guess that you could make like a tuto to add this function very interesting for everybody. Thank you.
Max

1 Like

Hi Max,
Since this simulator uses an external API from AccuWeather to perform requests and it has limited API calls, there is no way to provide any city as an option for the simulator.

But if you are interested, we can provide the Analysis for this simulator, so you can create your account on AccuWeather and generate your own API key.

Just create the is analysis, setup the environment variables, and create an action of type scheduler to run the analysis for you.

// Requires  the environment variables: 
// * weather_key: AccuWeather API KEY generated at https://developer.accuweather.com/apis
// * device_token: Device Token of the device that will receive the weather data.
// * city_key: Get the city key at https://developer.accuweather.com/accuweather-locations-api/apis/get/locations/v1/cities/search
const { Device, Analysis, Utils } = require('@tago-io/sdk');
const axios = require('axios');

function tagoObj(object_item, serie, prefix = "") {
  const result = [];
  for (const key in object_item) {
    if (ignore_vars.includes(key) || object_item[key] === null) continue;

    if (typeof object_item[key] === "object") {
      result.push({
        variable: (object_item[key].variable || `${prefix}${key}`).toLowerCase(),
        value: object_item[key].value,
        serie: object_item[key].serie || serie,
        metadata: object_item[key].metadata,
        location: object_item[key].location,
        unit: object_item[key].unit,
      });
    } else {
      result.push({
        variable: `${prefix}${key}`.toLowerCase(),
        value: object_item[key],
        serie,
      });
    }
  }

  return result;
}

async function getWeather({ id: city_id, city }, api_key) {
  const url = `http://dataservice.accuweather.com/currentconditions/v1/${city_id}?apikey=${api_key}&language=en-US&details=true`;
  const req = await axios.get(url).catch(console.log);
  const weather = req.data[0];
  return { ...weather, city_id, city_name: city };
}

function getAttribute(data_json = {}, param) {
  const json_depth = param.split('.');

  let current_step = data_json;
  for (const key of json_depth) {
    if (current_step[key] === null || current_step[key] === undefined) return null;

    current_step = current_step[key];
  }

  return current_step;
}

async function myAnalysis(context) {
  context.log('Running');
  const environment = Utils.envToJson(context.environment);

  const weather_key = environment.weather_key;
  const device = new Device({ token: environment.device_token });

  // TO get IDS, go to:
  // https://developer.accuweather.com/accuweather-locations-api/apis/get/locations/v1/cities/search
  // Look for Key attribute.
  const cityList = [
    { id: environment.city_id, city: 'N/A' },
    // { id: '329823', city: 'Raleigh' },
    // { id: '45881', city: 'São Paulo' },
    // { id: '328328', city: 'London' },
  ];

  let weather_result = await Promise.all(
    cityList.map(x => getWeather(x, weather_key).catch(() => null)),
  );
  weather_result = weather_result.filter((x, index) => {
    if (!x) {
      const city = cityList[index];
      context.log(
        `Error found when trying to fetch: ${city.id} - ${city.city}`,
      );
      return false;
    }
    return true;
  });

  const weather_data = weather_result
    .map((x) => {
      return tagoObj({
        temperature: {
          value: getAttribute(x, 'Temperature.Metric.Value'),
          unit: `°${getAttribute(x, 'Temperature.Metric.Unit')}`,
          metadata: {
            city: x.city_id,
            value: getAttribute(x, 'Temperature.Imperial.Value'),
            unit: `°${getAttribute(x, 'Temperature.Imperial.Unit')}`,
          },
        },
        wind_speed: {
          value: getAttribute(x, 'Wind.Speed.Metric.Value'),
          unit: `${getAttribute(x, 'Wind.Speed.Metric.Unit')}`,
          metadata: {
            city: x.city_id,
            value: getAttribute(x, 'Wind.Speed.Imperial.Value'),
            unit: `${getAttribute(x, 'Wind.Speed.Imperial.Unit')}`,
          },
        },
        wind_direction: {
          value: getAttribute(x, 'Wind.Direction.English'),
          metadata: {
            city: x.city_id,
          },
        },
        pressure: {
          value: getAttribute(x, 'Pressure.Metric.Value'),
          unit: `${getAttribute(x, 'Pressure.Metric.Unit')}`,
          metadata: {
            city: x.city_id,
            value: getAttribute(x, 'Pressure.Imperial.Value'),
            unit: `${getAttribute(x, 'Pressure.Imperial.Unit')}`,
          },
        },
        visibility: {
          value: getAttribute(x, 'Visibility.Metric.Value'),
          unit: `${getAttribute(x, 'Visibility.Metric.Unit')}`,
          metadata: {
            city: x.city_id,
            value: getAttribute(x, 'Visibility.Imperial.Value'),
            unit: `${getAttribute(x, 'Visibility.Imperial.Unit')}`,
          },
        },
        humidity: {
          value: getAttribute(x, 'RelativeHumidity'),
          unit: '%',
          metadata: {
            city: x.city_id,
          },
        },
        feel_temperature: {
          value: getAttribute(x, 'RealFeelTemperature.Metric.Value'),
          unit: `°${getAttribute(x, 'RealFeelTemperature.Metric.Unit')}`,
          metadata: {
            city: x.city_id,
            value: getAttribute(x, 'RealFeelTemperature.Imperial.Value'),
            unit: `°${getAttribute(x, 'RealFeelTemperature.Imperial.Unit')}`,
          },
        },
        precipitation: {
          value: getAttribute(
            x,
            'PrecipitationSummary.Precipitation.Metric.Value',
          ),
          unit: `${getAttribute(
            x,
            'PrecipitationSummary.Precipitation.Metric.Unit',
          )}`,
          metadata: {
            city: x.city_id,
            value: getAttribute(
              x,
              'PrecipitationSummary.Precipitation.Imperial.Value',
            ),
            unit: `${getAttribute(
              x,
              'PrecipitationSummary.Precipitation.Imperial.Unit',
            )}`,
          },
        },
        cloud: {
          value: getAttribute(x, 'WeatherText'),
          metadata: { city: x.city_id },
        },
      });
    })
    .reduce((final, item) => final.concat(item), []);

  await device.sendData(weather_data).then(context.log, context.log);
}

async function runMyAnalysis(context, scope) {
  myAnalysis(context, scope)
    .then(() => context.log('end'))
    .catch((e) => {
      context.log(e.message || JSON.stringify(e));
    });
}
// The analysis token in only necessary to run the analysis outside Tago
module.exports = new Analysis(runMyAnalysis);

working like a charm ! thank you

1 Like

Hi Vitor, I’m trying to set this Accuweather API up and I’m running into a problem where the console gives me an error message:
[2021-08-20 18:49:22] ReferenceError: Analysis is not defined
[2021-08-20 18:49:22] Starting analysis 612037a42256960018f69589
I think I followed all the other steps but this is my first analysis and I’m not a Java programmer so hard to know where I went wrong. Thank you!

you may have missed the following line at top of the code:

const { Device, Analysis, Utils } = require(’@tago-io/sdk’);

1 Like

Thanks for the response. I copied the code exactly as presented including the // comments. I took them out so now the first line is the const command and I’m getting the following errors:

[2021-08-22 19:28:23] TypeError: Cannot read property ‘run’ of undefined
[2021-08-22 19:28:23] Starting analysis 612037a42256960018f69589

Appreciate any help you can provide. Thanks!

It does look like the analysis is not finding the export function to run.

Did you miss the last line of the code?

module.exports = new Analysis(runMyAnalysis);

If you are having that much trouble, you can get the analysis template from here: https://admin.tago.io/template/5e1e1cd306fbee00265d5ea7

Vitor,
I copied the code directly and now am getting a different error:

[2021-08-24 08:22:23] ignore_vars is not defined
[2021-08-24 08:22:23] Running
[2021-08-24 08:22:23] Starting analysis

Obrigado!

It does look like an issue on payload parser of the device you’re using. Try creating a new device with Custom HTTPs and use it’s token instead.

I set-up a new device and am getting the same error:

[2021-08-25 13:26:41] ignore_vars is not defined
[2021-08-25 13:26:40] Running
[2021-08-25 13:26:40] Starting analysis 61252c0996c41800180605d9

Do I need to do anything else to the device besides custom https and using it’s token in the environmental variable for the analysis?

1 Like

Well good news - I looked up some of the code examples and realized I needed to remove the line referencing ignore_vars and it worked like a champ.
Obrigado!

1 Like