Last active
November 28, 2021 19:34
-
-
Save vnavascues/d8c25cc6509b3af921d3566335935d6e 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 metric imperial | |
* --------------------------------------------------- | |
* 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 { | |
uint256 locationKey; | |
string endpoint; | |
string lat; | |
string lon; | |
string units; | |
} | |
struct LocationResult { | |
uint256 locationKey; | |
string name; | |
bytes2 countryCode; | |
} | |
struct CurrentConditionsResult { | |
uint256 timestamp; | |
uint24 precipitationPast12Hours; | |
uint24 precipitationPast24Hours; | |
uint24 precipitationPastHour; | |
uint24 pressure; | |
int16 temperature; | |
uint16 windDirectionDegrees; | |
uint16 windSpeed; | |
uint8 precipitationType; | |
uint8 relativeHumidity; | |
uint8 uvIndex; | |
uint8 weatherIcon; | |
} | |
// Maps | |
mapping(bytes32 => CurrentConditionsResult) public requestIdCurrentConditionsResult; | |
mapping(bytes32 => LocationResult) public requestIdLocationResult; | |
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 location information for the given coordinates. | |
* @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). | |
*/ | |
function requestLocation( | |
bytes32 _specId, | |
uint256 _payment, | |
string calldata _lat, | |
string calldata _lon | |
) public { | |
Chainlink.Request memory req = buildChainlinkRequest(_specId, address(this), this.fulfillLocation.selector); | |
req.add("endpoint", "location"); // NB: not required if it has been hardcoded in the job spec | |
req.add("lat", _lat); | |
req.add("lon", _lon); | |
bytes32 requestId = requestOracleData(req, _payment); | |
// Below this line is just an example of usage | |
storeRequestParams(requestId, 0, "location", _lat, _lon, ""); | |
} | |
/** | |
* @notice Returns the current weather conditions of a location by ID. | |
* @param _specId the jobID. | |
* @param _payment the LINK amount in Juels (i.e. 10^18 aka 1 LINK). | |
* @param _locationKey the location ID. | |
* @param _units the measurement system ("metric" or "imperial"). | |
*/ | |
function requestCurrentConditions( | |
bytes32 _specId, | |
uint256 _payment, | |
uint256 _locationKey, | |
string calldata _units | |
) public { | |
Chainlink.Request memory req = buildChainlinkRequest( | |
_specId, | |
address(this), | |
this.fulfillCurrentConditions.selector | |
); | |
req.add("endpoint", "current-conditions"); // NB: not required if it has been hardcoded in the job spec | |
req.addUint("locationKey", _locationKey); | |
req.add("units", _units); | |
bytes32 requestId = requestOracleData(req, _payment); | |
// Below this line is just an example of usage | |
storeRequestParams(requestId, _locationKey, "current-conditions", "0", "0", _units); | |
} | |
/** | |
* @notice Returns the current weather conditions of a location for the given coordinates. | |
* @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 | |
storeRequestParams(requestId, 0, "location-current-conditions", _lat, _lon, _units); | |
} | |
/* ========== CONSUMER FULFILL FUNCTIONS ========== */ | |
/** | |
* @notice Consumes the data returned by the node job on a particular request. | |
* @dev Only when `_locationFound` is true, both `_locationFound` will contain meaningful data (as bytes). This | |
* function body is just an example of usage. | |
* @param _requestId the request ID for fulfillment. | |
* @param _locationFound true if a location was found for the given coordinates, otherwise false. | |
* @param _locationResult the location information (encoded as LocationResult). | |
*/ | |
function fulfillLocation( | |
bytes32 _requestId, | |
bool _locationFound, | |
bytes memory _locationResult | |
) public recordChainlinkFulfillment(_requestId) { | |
if (_locationFound) { | |
storeLocationResult(_requestId, _locationResult); | |
} | |
} | |
/** | |
* @notice Consumes the data returned by the node job on a particular request. | |
* @param _requestId the request ID for fulfillment. | |
* @param _currentConditionsResult the current weather conditions (encoded as CurrentConditionsResult). | |
*/ | |
function fulfillCurrentConditions(bytes32 _requestId, bytes memory _currentConditionsResult) | |
public | |
recordChainlinkFulfillment(_requestId) | |
{ | |
storeCurrentConditionsResult(_requestId, _currentConditionsResult); | |
} | |
/** | |
* @notice Consumes the data returned by the node job on a particular request. | |
* @dev Only when `_locationFound` is true, both `_locationFound` and `_currentConditionsResult` will contain | |
* meaningful data (as bytes). This function body is just an example of usage. | |
* @param _requestId the request ID for fulfillment. | |
* @param _locationFound true if a location was found for the given coordinates, otherwise false. | |
* @param _locationResult the location information (encoded as LocationResult). | |
* @param _currentConditionsResult the current weather conditions (encoded as CurrentConditionsResult). | |
*/ | |
function fulfillLocationCurrentConditions( | |
bytes32 _requestId, | |
bool _locationFound, | |
bytes memory _locationResult, | |
bytes memory _currentConditionsResult | |
) public recordChainlinkFulfillment(_requestId) { | |
if (_locationFound) { | |
storeLocationResult(_requestId, _locationResult); | |
storeCurrentConditionsResult(_requestId, _currentConditionsResult); | |
} | |
} | |
/* ========== PRIVATE FUNCTIONS ========== */ | |
function storeRequestParams( | |
bytes32 _requestId, | |
uint256 _locationKey, | |
string memory _endpoint, | |
string memory _lat, | |
string memory _lon, | |
string memory _units | |
) private { | |
RequestParams memory requestParams; | |
requestParams.locationKey = _locationKey; | |
requestParams.endpoint = _endpoint; | |
requestParams.lat = _lat; | |
requestParams.lon = _lon; | |
requestParams.units = _units; | |
requestIdRequestParams[_requestId] = requestParams; | |
} | |
function storeLocationResult(bytes32 _requestId, bytes memory _locationResult) private { | |
LocationResult memory result = abi.decode(_locationResult, (LocationResult)); | |
requestIdLocationResult[_requestId] = result; | |
} | |
function storeCurrentConditionsResult(bytes32 _requestId, bytes memory _currentConditionsResult) private { | |
CurrentConditionsResult memory result = abi.decode(_currentConditionsResult, (CurrentConditionsResult)); | |
requestIdCurrentConditionsResult[_requestId] = result; | |
} | |
/* ========== 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