Weather Alert API

You can use the OWM API to create triggers.

Each trigger represents the check if a set of conditions on certain weather parameter values are met over certain geographic areas.

Whenever a condition is met, an alert is fired and stored, and can be retrieved by polling the API.

A full example first

Hands-on! This is a full example of how to use the Alert API. Check further for details about the involved object types.

from pyowm import OWM
from pyowm.utils import geo
from pyowm.alertapi30.enums import WeatherParametersEnum, OperatorsEnum, AlertChannelsEnum
from pyowm.alertapi30.condition import Condition

# obtain an AlertManager instance
owm = OWM('apikey')
am = owm.alert_manager()

# -- areas --
geom_1 = geo.Point(lon, lat)  # available types: Point, MultiPoint, Polygon, MultiPolygon
geom_1.geojson()
'''
{
  "type": "Point",
  "coordinates":[ lon, lat ]
}
'''
geom_2 = geo.MultiPolygon([[lon1, lat1], [lon2, lat2], [lon3, lat3], [lon1, lat1]]
                          [[lon7, lat7], [lon8, lat8], [lon9, lat9], [lon7, lat7]])


# -- conditions --
condition_1 = Condition(WeatherParametersEnum.TEMPERATURE,
                        OperatorsEnum.GREATER_THAN,
                        313.15)  # kelvin
condition_2 = Condition(WeatherParametersEnum.CLOUDS,
                        OperatorsEnum.EQUAL,
                        80) # clouds % coverage

# -- triggers --

# create a trigger
trigger = am.create_trigger(start_after_millis_=355000, end_after_millis=487000,
                            conditions=[condition_1, condition_2],
                            area=[geom_1, geom_2],
                            alert_channel=AlertChannelsEnum.OWM_API)

# read all triggers
triggers_list = am.get_triggers()

# read one named trigger
trigger_2 = am.get_trigger('trigger_id')

# update a trigger
am.update_trigger(trigger_2)

# delete a trigger
am.delete_trigger(trigger_2)

# -- alerts --

# retrieved from the local parent Trigger obj...
alerts_list = trigger.get_alerts()
alerts_list = trigger.get_alerts_since('2018-01-09T23:07:24Z')  # useful for polling alerts
alerts_list = trigger.get_alerts_on(WeatherParametersEnum.TEMPERATURE)
alert = trigger.get_alert('alert_id')

# ...or retrieved from the remote API
alerts_list_alternate = am.get_alerts_for(trigger)
alert_alternate = am.get_alert('alert_id')


# delete all or one alert
am.delete_all_alerts_for(trigger)
am.delete_alert_for(trigger, alert)

Alert API object model

This is the Alert API object model:

  • Trigger: collection of alerts to be met over specified areas and within a specified time frame according to specified weather params conditions
  • Condition: rule for matching a weather measurement with a specified threshold
  • Alert: whenever a condition is met, an alert is created (or updated) and can be polled to verify when it has been met and what the actual weather param value was.
  • Area: geographic area over which the trigger is checked
  • AlertChannel: as OWM plans to add push-oriented alert channels (eg. push notifications), we need to encapsulate this into a specific class

and then you have an AlertManager class that you will need to instantiate to operatively interact with the Alert API

Area

The area describes the geographic boundaries over which a trigger is evaluated. Don’t be mislead by the term “area”: this can refer also to a specific geopoint or a set of them, besides - of course - polygons and set of polygons.

Any of the geometry subtypes found in pyowm.utils.geo module (point, multipoint, polygon, multipolygon) are fine to use.

Example:

from pyowm.utils import geo
point = geo.Point(20.8, 30.9)  # available geometry types: Point, MultiPoint, Polygon, MultiPolygon
point.geojson()
'''
{
  "type": "Point",
  "coordinates":[ 20.8, 30.9 ]
}
'''

Defining complex geometries is sometimes difficult, but in most cases you just need to set triggers upon cities: that’s why we’ve added a method to the pyowm.weatherapi25.cityidregistry.CityIDRegistry registry that returns the geopoints that correspond to one or more named cities:

import pyowm
owm = pyowm.OWM('your-API-key')
reg = owm.city_id_registry()
geopoints = reg.geopoints_for('London', country='GB')

But still some very spread cities (think of London,GB or Los Angeles,CA) exist and therefore approximating a city to a single point is not accurate at all: that’s why we’ve added a nice method to get a squared polygon that is circumscribed to the circle having a specified geopoint as its centre. This makes it possible to easily get polygons to cover large squared areas and you would only need to specify the radius of the circle. Let’s do it for London,GB in example:

geopoints = reg.geopoints_for('London', country='GB')
centre = geopoints[0] # the list has only 1 geopoint
square_polygon = centre.bounding_square_polygon(inscribed_circle_radius_km=12) # radius of the inscribed circle in kms (defaults to: 10)

Please, notice that if you specify big values for the radius you need to take care about the projection of geographic coordinates on a proper geoid: this means that if you don’t, the polygon will only approximate a square.

Topology is set out as stated by GeoJSON

Moreover, there is a useful factory for Areas: pyowm.utils.geo.GeometryBuilder.build(), that you can use to turn a geoJSON standard dictionary into the corresponding topology type:

from pyowm.utils.geo import GeometryBuilder
the_dict = {
    "type": "Point",
    "coordinates": [53, 37]
}
geom = GeometryBuilder.build(the_dict)
type(geom)  # <pyowm.utils.geo.Point>

You can bind multiple pyowm.utils.geo geometry types to a Trigger: a list of such geometries is considered to be the area on which conditions of a Trigger are checked.

Condition

A condition is a numeric rule to be checked on a named weather variable. Something like:

  - VARIABLE X IS GREATER THAN AMOUNT_1
  - VARIABLE Y IS EQUAL TO AMOUNT_2
  - VARIABLE Z IS DIFFERENT FROM AMOUNT_3

GREATER, EQUAL TO, DIFFERENT FROM are called comparison expressions or operators; VARIABLE X, Y, Z are called target parameters.

Each condition is then specified by:

  • target_param: weather parameter to be checked. Can be: temp, pressure, humidity, wind_speed, wind_direction, clouds.
  • expression: str, operator for the comparison. Can be: $gt, $gte, $lt, $lte, $eq, $ne`
  • amount: number, the comparison value

Conditions are bound to Triggers, as they are set on Trigger instantiation.

As Conditions can be only set on a limited number of weather variables and can be expressed only through a closed set of comparison operators, convenient enumerators are offered in module pyowm.alertapi30.enums:

  • WeatherParametersEnum –> what weather variable to set this condition on
  • OperatorsEnum –> what comparison operator to use on the weather parameter

Use enums so that you don’t have to remember the syntax of operators and weather params that is specific to the OWM Alert API. Here is how you use them:

from pyowm.alertapi30 import enums
enums.WeatherParametersEnum.items()      # [('TEMPERATURE', 'temp'), ('WIND_SPEED', 'wind_speed'), ... ]
enums.WeatherParametersEnum.TEMPERATURE  # 'temp'
enums.WeatherParametersEnum.WIND_SPEED   # 'wind_speed'

enums.OperatorsEnum.items()              # [('GREATER_THAN', '$gt'), ('NOT_EQUAL', '$ne'), ... ]
enums.OperatorsEnum.GREATER_THAN         # '$gt'
enums.OperatorsEnum.NOT_EQUAL            # '$ne'

Here is an example of conditions:

from pyowm.alertapi30.condition import Condition
from pyowm.alertapi30 import enums

# this condition checks if the temperature is bigger than 313.15 Kelvin degrees
condition = Condition(enums.WeatherParametersEnum.TEMPERATURE,
                      enums.OperatorsEnum.GREATER_THAN,
                      313.15)

Remember that each Condition is checked by the OWM Alert API on the geographic area that you need to specify!

You can bind multiple pyowm.alertapi30.condition.Condition objects to a Trigger: each Alert will be fired when a specific Condition is met on the area.

Alert

As said, whenever one or more conditions are met on a certain area, an alert is fired (this means that “the trigger triggers”)

If the condition then keeps on being met, more and more alerts will be spawned by the OWM Alert API. You can retrieve such alerts by polling the OWM API (see below about how to do it).

Each alert is represented by PyOWM as a pyowm.alertapi30.alert.Alert instance, having:

  • a unique identifier
  • timestamp of firing
  • a link back to the unique identifier of the parent pyowm.alertapi30.trigger.Trigger object instance
  • the list of met conditions (each one being a dict containing the Condition object and the weather parameter value that actually made the condition true)
  • the geocoordinates where the condition has been met (they belong to the area that had been specified for the Trigger)

Example:

from pyowm.alertapi30.condition import Condition
from pyowm.alertapi30 import enums
from pyowm.alertapi30.alert import Alert

condition = Condition(enums.WeatherParametersEnum.TEMPERATURE,
                      enums.OperatorsEnum.GREATER_THAN,
                      356.15)

alert = Alert('alert-id',                   # alert id
              'parent-trigger-id',          # parent trigger's id
              [{                            # list of met conditions
                    "current_value": 326.4,
                    "condition": condition
               }],
               {"lon": 37, "lat": 53},      # coordinates
               1481802100000                # fired on
)

As you see, you’re not meant to create alerts, but PyOWM is supposed to create them for you as they are fired by the OWM API.

AlertChannel

Something that OWM envisions, but still does not offer. Possibly, when you will setup a trigger you shall also specify the channels you want to be notified on: that’s why we’ve added a reference to a list of AlertChannel instances directly on the Trigger objects (the list now only points to the default channel)

A useful enumerator is offered in module pyowm.alertapi30.enums: AlertChannelsEnum (says what channels should the alerts delivered to)

As of today, the default AlertChannel is: AlertChannelsEnum.OWM_API_POLLING, and is the only one available.

Trigger

As said, each trigger represents the check if a set of conditions on certain weather parameter values are met over certain geographic areas.

A Trigger is the local proxy for the corresponding entry on the OWM API: Triggers can be operated through pyowm.alertapi30.alertmanager.AlertManager instances.

Each Trigger has these attributes:

  • start_after_millis: with respect to the time when the trigger will be created on the Alert API, how many milliseconds after should it begin to be checked for conditions matching
  • end_after_millis: with respect to the time when the trigger will be created on the Alert API, how many milliseconds after should it end to be checked for conditions matching
  • alerts: a list of pyowm.alertapi30.alert.Alert instances, which are the alerts that the trigger has fired so far
  • conditions: a list of pyowm.alertapi30.condition.Condition instances
  • area: a list of pyowm.utils.geo.Geometry instances, representing the geographic area on which the trigger’s conditions need to be checked
  • alertChannels: list of pyowm.alertapi30.alert.AlertChannel objects, representing which channels this trigger is notifying to

Notes on trigger’s time period By design, PyOWM will only use the after operator to communicate time periods for Triggers to the Alert API. will send them to the API using the after operator.

The millisecond start/end deltas will be calculated with respect to the time when the Trigger record is created on the Alert API using pyowm.alertapi30.alertmanager.AlertManager.create_trigger

AlertManager

The OWM main entry point object allows you to get an instance of an pyowm.alertapi30.alert_manager.AlertManager object: use it to interact with the Alert API and create/read/update/delete triggers and read/delete the related alerts.

Here is how to instantiate an AlertManager:

from pyowm import OWM

owm = OWM(API_Key='my-API-key')
am = owm.alert_manager()

Then you can do some nice things with it:

  • create a trigger
  • read all of your triggers
  • read a named trigger
  • modify a named trigger
  • delete a named trigger
  • read all the alerts fired by a named trigger
  • read a named alert
  • delete a named alert
  • delete all of the alerts for a named trigger