Created
October 25, 2021 17:57
-
-
Save vnavascues/cde12f67ad2b9a1d256e260d19e8baae to your computer and use it in GitHub Desktop.
An AccuWeather Consumer contract
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.4; | |
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol"; | |
/** | |
* **** Data Conversions **** | |
* | |
* countryCode (bytes2) | |
* -------------------- | |
* ISO 3166 alpha-2 codes encoded as bytes2 | |
* See: https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes | |
* | |
* | |
* precipitationType (uint8) | |
* -------------------------- | |
* Value Type | |
* -------------------------- | |
* 0 No precipitation | |
* 1 Rain | |
* 2 Snow | |
* 3 Ice | |
* 4 Mixed | |
* | |
* | |
* weatherIcon (uint8) | |
* ------------------- | |
* Each icon number is related with an image and a text | |
* See: https://developer.accuweather.com/weather-icons | |
* | |
* | |
* Decimals to integers (both metric & imperial units) | |
* --------------------------------------------------- | |
* Condition Conversion | |
* --------------------------------------------------- | |
* precipitationPast12Hours multiplied by 100 | |
* precipitationPast24Hours multiplied by 100 | |
* precipitationPastHour multiplied by 100 | |
* pressure multiplied by 100 | |
* temperature multiplied by 10 | |
* windSpeed multiplied by 10 | |
* | |
* | |
* Current weather conditions units per system | |
* --------------------------------------------------- | |
* Condition imperial metric | |
* --------------------------------------------------- | |
* precipitationPast12Hours mm in | |
* precipitationPast24Hours mm in | |
* precipitationPastHour mm in | |
* pressure mb inHg | |
* temperature C F | |
* windSpeed km/h mi/h | |
* | |
* | |
* Other resources | |
* --------------- | |
* AccuWeather API docs: | |
* http://apidev.accuweather.com/developers/ | |
* | |
* Locations API Response Parameters: | |
* http://apidev.accuweather.com/developers/locationAPIparameters#responseParameters | |
* | |
* Current Conditions API Response Parameters: | |
* http://apidev.accuweather.com/developers/currentConditionsAPIParameters#responseParameters | |
*/ | |
/** | |
* @title A consumer contract for AccuWeather EA 'location-current-conditions' endpoint. | |
* @author LinkPool | |
* @notice Request the current weather conditions for the given location coordinates (i.e. latitude and longitude). | |
*/ | |
contract AccuweatherConsumer is ChainlinkClient { | |
using Chainlink for Chainlink.Request; | |
/* ========== CONSUMER STATE VARIABLES ========== */ | |
struct RequestParams { | |
string lat; | |
string lon; | |
string units; | |
} | |
struct Location { | |
uint256 locationKey; | |
string lat; | |
string lon; | |
string name; | |
bytes2 countryCode; | |
} | |
struct CurrentConditions { | |
uint256 locationKey; | |
uint256 timestamp; | |
uint24 precipitationPast12Hours; | |
uint24 precipitationPast24Hours; | |
uint24 precipitationPastHour; | |
uint24 pressure; | |
int16 temperature; | |
uint16 windDirectionDegrees; | |
uint16 windSpeed; | |
uint8 precipitationType; | |
uint8 relativeHumidity; | |
uint8 uvIndex; | |
uint8 weatherIcon; | |
} | |
struct LocationCurrentConditionsResult { | |
uint256 locationKey; | |
uint256 timestamp; | |
uint24 precipitationPast12Hours; | |
uint24 precipitationPast24Hours; | |
uint24 precipitationPastHour; | |
uint24 pressure; | |
bytes2 countryCode; | |
int16 temperature; | |
uint16 windDirectionDegrees; | |
uint16 windSpeed; | |
uint8 precipitationType; | |
uint8 relativeHumidity; | |
uint8 uvIndex; | |
uint8 weatherIcon; | |
string name; | |
} | |
// Maps | |
mapping(bytes32 => CurrentConditions) public requestIdCurrentConditions; | |
mapping(bytes32 => Location) public requestIdLocation; | |
mapping(bytes32 => RequestParams) public requestIdRequestParams; | |
/* ========== CONSTRUCTOR ========== */ | |
/** | |
* @param _link the LINK token address. | |
* @param _oracle the Operator.sol contract address. | |
*/ | |
constructor(address _link, address _oracle) { | |
setChainlinkToken(_link); | |
setChainlinkOracle(_oracle); | |
} | |
/* ========== CONSUMER REQUEST FUNCTIONS ========== */ | |
/** | |
* @notice Returns the current weather conditions of a location for the given coordinates. | |
* @dev Result is encoded as LocationCurrentConditionsResult (tuple). When no location is found for the given | |
* coordinates 'locationKey' value is 0 (AccuWeather Locations API does not allow 0 as a location Key). | |
* @param _specId the jobID. | |
* @param _payment the LINK amount in Juels (i.e. 10^18 aka 1 LINK). | |
* @param _lat the latitude (WGS84 standard, from -90 to 90). | |
* @param _lon the longitude (WGS84 standard, from -180 to 180). | |
* @param _units the measurement system ("metric" or "imperial"). | |
*/ | |
function requestLocationCurrentConditions( | |
bytes32 _specId, | |
uint256 _payment, | |
string calldata _lat, | |
string calldata _lon, | |
string calldata _units | |
) public { | |
Chainlink.Request memory req = buildChainlinkRequest( | |
_specId, | |
address(this), | |
this.fulfillLocationCurrentConditions.selector | |
); | |
req.add("endpoint", "location-current-conditions"); // NB: not required if it has been hardcoded in the job spec | |
req.add("lat", _lat); | |
req.add("lon", _lon); | |
req.add("units", _units); | |
bytes32 requestId = requestOracleData(req, _payment); | |
// Below this line is just an example of usage | |
RequestParams memory requestParams; | |
requestParams.lat = _lat; | |
requestParams.lon = _lon; | |
requestParams.units = _units; | |
requestIdRequestParams[requestId] = requestParams; | |
} | |
/* ========== CONSUMER FULFILL FUNCTIONS ========== */ | |
/** | |
* @notice Consumes the data returned by the node job on a particular request. | |
* @param _requestId The request ID for fulfillment. | |
* @param _result the current weather conditions of the location (encoded as tuple). | |
*/ | |
function fulfillLocationCurrentConditions(bytes32 _requestId, bytes memory _result) | |
public | |
recordChainlinkFulfillment(_requestId) | |
{ | |
// NB: the expression below is required for decoding the result | |
LocationCurrentConditionsResult memory result = abi.decode(_result, (LocationCurrentConditionsResult)); | |
// Below this line is just an example of usage | |
Location memory location; | |
CurrentConditions memory currentConditions; | |
location.lat = requestIdRequestParams[_requestId].lat; | |
location.lon = requestIdRequestParams[_requestId].lon; | |
// If 'locationKey' is gt 0 a location was found | |
if (result.locationKey > 0) { | |
// Location | |
location.locationKey = result.locationKey; | |
location.name = result.name; | |
location.countryCode = result.countryCode; | |
// CurrentConditions | |
currentConditions.locationKey = result.locationKey; | |
currentConditions.timestamp = result.timestamp; | |
currentConditions.precipitationPast12Hours = result.precipitationPast12Hours; | |
currentConditions.precipitationPast24Hours = result.precipitationPast24Hours; | |
currentConditions.precipitationPastHour = result.precipitationPastHour; | |
currentConditions.pressure = result.pressure; | |
currentConditions.temperature = result.temperature; | |
currentConditions.windDirectionDegrees = result.windDirectionDegrees; | |
currentConditions.windSpeed = result.windSpeed; | |
currentConditions.precipitationType = result.precipitationType; | |
currentConditions.relativeHumidity = result.relativeHumidity; | |
currentConditions.uvIndex = result.uvIndex; | |
currentConditions.weatherIcon = result.weatherIcon; | |
} | |
requestIdLocation[_requestId] = location; | |
requestIdCurrentConditions[_requestId] = currentConditions; | |
} | |
/* ========== OTHER FUNCTIONS ========== */ | |
function getOracleAddress() external view returns (address) { | |
return chainlinkOracleAddress(); | |
} | |
function setOracle(address _oracle) external { | |
setChainlinkOracle(_oracle); | |
} | |
function withdrawLink() public { | |
LinkTokenInterface linkToken = LinkTokenInterface(chainlinkTokenAddress()); | |
require(linkToken.transfer(msg.sender, linkToken.balanceOf(address(this))), "Unable to transfer"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment