// Abstract ------------------------------------------------------------------------------------------------------------------------------

This sample fetchs data from openweathermap.org (as JSON) and import it as knowledge. You will need an API key (free) to try/use this sample (see http://openweathermap.org/appid)

// Examples ------------------------------------------------------------------------------------------------------------------------------

$ ./fizz.x64 ./etc/samples/weather.fizz -c api.key=\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"
fizz 0.2.0-X (20180218.1219) [x64|8|w]

load : loading ./etc/samples/weather.fizz ...
load : loaded ./etc/samples/weather.fizz in 0.088s
repeal: city.weather.latest(5808079, _)
assert: city.weather.latest(5808079, 1519150500)
assert: city.weather.stamp(5808079, 1519150500)
assert: city.name(5808079, Redmond)
assert: weather.condition(600, Snow, "light snow")
assert: weather.condition(701, Mist, mist)
assert: city.weather.details(5808079, 1519150500, temp, -0.130000)
assert: city.weather.details(5808079, 1519150500, pressure, 1022)
assert: city.weather.details(5808079, 1519150500, humidity, 86)
assert: city.weather.condition(5808079, 1519150500, 600)
assert: city.weather.details(5808079, 1519150500, temp_min, -2)
assert: city.weather.condition(5808079, 1519150500, 701)
assert: city.weather.details(5808079, 1519150500, temp_max, 1)
Redmond: light snow
Redmond: mist
Redmond: -0.130000
repeal: city.weather.latest(5856195, _)
assert: city.weather.latest(5856195, 1519153020)
assert: city.weather.stamp(5856195, 1519153020)
assert: city.name(5856195, Honolulu)
assert: weather.condition(801, Clouds, "few clouds")
assert: city.weather.details(5856195, 1519153020, temp, 21.650000)
assert: city.weather.condition(5856195, 1519153020, 801)
assert: city.weather.details(5856195, 1519153020, pressure, 1015)
assert: city.weather.details(5856195, 1519153020, humidity, 64)
assert: city.weather.details(5856195, 1519153020, temp_min, 20)
assert: city.weather.details(5856195, 1519153020, temp_max, 23)
Honolulu: 21.650000
Honolulu: few clouds
repeal: city.weather.latest(2988507, _)
assert: city.weather.latest(2988507, 1519153200)
assert: city.weather.stamp(2988507, 1519153200)
assert: city.name(2988507, Paris)
assert: weather.condition(500, Rain, "light rain")
assert: weather.condition(615, Snow, "light rain and snow")
assert: city.weather.details(2988507, 1519153200, temp, 4.120000)
assert: city.weather.details(2988507, 1519153200, pressure, 1019)
assert: city.weather.condition(2988507, 1519153200, 500)
assert: city.weather.details(2988507, 1519153200, humidity, 75)
assert: city.weather.details(2988507, 1519153200, temp_min, 3)
assert: city.weather.condition(2988507, 1519153200, 615)
assert: city.weather.details(2988507, 1519153200, temp_max, 5)
Paris: 4.120000
Paris: light rain
Paris: light rain and snow
repeal: city.weather.latest(5808079, _)
assert: city.weather.latest(5808079, 1519154880)
assert: city.weather.stamp(5808079, 1519154880)
assert: city.name(5808079, Redmond)
assert: weather.condition(600, Snow, "light snow")
assert: weather.condition(701, Mist, mist)
assert: city.weather.details(5808079, 1519154880, temp, 0.550000)
assert: weather.condition(500, Rain, "light rain")
assert: city.weather.details(5808079, 1519154880, pressure, 1022)
assert: city.weather.details(5808079, 1519154880, humidity, 100)
assert: city.weather.condition(5808079, 1519154880, 600)
assert: city.weather.details(5808079, 1519154880, temp_min, -1)
assert: city.weather.details(5808079, 1519154880, temp_max, 2)
assert: city.weather.condition(5808079, 1519154880, 701)
assert: city.weather.condition(5808079, 1519154880, 500)
Redmond: 0.550000
Redmond: light snow
Redmond: mist
Redmond: light rain
repeal: city.weather.latest(2988507, _)
assert: city.weather.latest(2988507, 1519155000)
assert: city.weather.stamp(2988507, 1519155000)
assert: city.name(2988507, Paris)
assert: weather.condition(500, Rain, "light rain")
assert: weather.condition(615, Snow, "light rain and snow")
assert: city.weather.details(2988507, 1519155000, temp, 4.130000)
assert: city.weather.condition(2988507, 1519155000, 500)
assert: city.weather.details(2988507, 1519155000, pressure, 1019)
assert: city.weather.details(2988507, 1519155000, humidity, 75)
assert: city.weather.condition(2988507, 1519155000, 615)
assert: city.weather.details(2988507, 1519155000, temp_min, 3)
assert: city.weather.details(2988507, 1519155000, temp_max, 5)
Paris: 4.130000
Paris: light rain
Paris: light rain and snow
save : completed in 0.016s.
 
// Code ----------------------------------------------------------------------------------------------------------------------------------

// query the latest temperature for a given city
weather.temp {

    (:name,:v) :-   #city.name(:id,:name),
                    #city.weather.latest(:id,:dt),
                    #city.weather.details(:id,:dt,temp,:v);

}

// query the latest conditions for a given city
weather.cond {

    (:name,:d) :-   #city.name(:id,:name),
                    #city.weather.latest(:id,:dt),
                    #fzz.collect([],city.weather.condition(:id,:dt,:l),_,{tmo=0.1}),
                    #code.to.desc(:l,:d);

}

// wrap the primitive 'assert' so that what is being asserted during execution can be more easily seen (in the console)
assert {

    (:f) :- console.puts("assert: ",:f), assert(:f);

}

// wrap the primitive 'repeal' so that what is being repealed during execution can be more easily seen (in the console)
repeal {

    (:f) :- console.puts("repeal: ",:f), repeal(:f);

}

// a ticking elemental (10s interval) used to automatically save the data received so far
auto.save.tick {class = FZZCTicker, tick = 10} {

}

// performs the automatic saving of all weather data knowledge
auto.save {

    () :-   @auto.save.tick(:n,_),
            console.exec(save("weather.data.fizz",city.name,city.weather.stamp,city.weather.latest,city.weather.condition,city.weather.details,weather.condition));

}

// will store the city-id / city-name mapping
city.name {

}

// will store the latest stamp received for a city
city.weather.latest {

}

// will store the time-stamp received per city, we will it to ignore the data retrieved from the service when they haven't changed
city.weather.stamp {

    class    = MRKCLettered,
    no.match = fail

} {

}

// will store a city's weather conditions (over time)
city.weather.condition {

}

// will store a city's weather details (temperature, pressure ...)
city.weather.details {

}

// will store the condition-id / condition-description mapping
weather.condition {

}

// a web API puller elemental, fetching data every 5 seconds
web.weather.puller {

    class           = FZZCWebAPIPuller,
    tick            = 5.0,
    url.host        = "http://api.openweathermap.org",
    url.path        = "/data/2.5/weather",
    url.query       = { q = Redmond, units = metric, APPID = $api.key }

} {

}

// a web API puller elemental, fetching data every 5 seconds
web.weather.puller {

    class           = FZZCWebAPIPuller,
    tick            = 5.0,
    url.host        = "http://api.openweathermap.org",
    url.path        = "/data/2.5/weather",
    url.query       = { q = Honolulu, units = metric, APPID = $api.key }

} {

}

// a web API puller elemental, fetching data every 5 seconds
web.weather.puller {

    class           = FZZCWebAPIPuller,
    tick            = 5.0,
    url.host        = "http://api.openweathermap.org",
    url.path        = "/data/2.5/weather",
    url.query       = { q = Paris, units = metric, APPID = $api.key }

} {

}

// the main entry point for the data pulled from the web sites
web.weather.input {

    () :-   @web.weather.puller(:t,:s?[neq(200)],_,:content),
            frm.fetch(:content,message,:message),
            console.puts("pulling error: ",:s," ",:message);

    () :-   @web.weather.puller(:t,200,_,:content),
            frm.fetch(:content,id,:id),
            frm.fetch(:content,name,:city),
            frm.fetch(:content,dt,:dt),
            !#city.weather.stamp(:id,:dt),
            change([city.weather.latest(:id,_)],[city.weather.latest(:id,:dt)]),
            #assert(city.weather.stamp(:id,:dt)),
            #assert(city.name(:id,:city)),
            frm.fetch(:content,:key,:value),
            #web.weather.parse(:id,:dt,:key,:value);

}

// parse some of the data received from the web service
web.weather.parse {

    (:city.id,:dt,weather,:l?[is.list])^    :- #web.weather.parse.weather(:city.id,:dt,:l);
    (:city.id,:dt,main,:f?[is.frame])^      :- #web.weather.parse.main(:city.id,:dt,:f);

}

// parse the weather condition and assert the corresponding statements
web.weather.parse.weather {

    (:city.id,:dt,:l) :-    lst.item(:l,_,:f),
                            frm.fetch(:f,id,:i), frm.fetch(:f,main,:m), frm.fetch(:f,description,:d),
                            #assert(weather.condition(:i,:m,:d)),
                            #assert(city.weather.condition(:city.id,:dt,:i));

}

// parse the weather details
web.weather.parse.main {

    (:city.id,:dt,:f)^ :-  frm.fetch(:f,:label,:value), #assert(city.weather.details(:city.id,:dt,:label,:value));

}

// display (on the console) the temperature and weather condition for each city, whenever we receive new data
web.weather.watcher {

    () :- @city.weather.details(:id,_,temp,:v), #city.name(:id,:n), console.puts(:n,": ",:v);
    () :- @city.weather.condition(:id,_,:c), #city.name(:id,:n), #weather.condition(:c,_,:d), console.puts(:n,": ",:d);

}

// convert a list of condition codes to a list of descriptions
code.to.desc {

    ([],[])             ^:- true;
    ([:e],[:f])         ^:- #weather.condition(:e,_,:f);
    ([:h|:t],[:h2|:t2]) ^:- #code.to.desc(:t,:t2), #weather.condition(:h,_,:h2);

}

// ---------------------------------------------------------------------------------------------------------------------------------------

[Home] [Email] [Twitter] [LinkedIn]