Skip to content

Instantly share code, notes, and snippets.

@vnavascues
Created October 25, 2021 17:57
Show Gist options
  • Save vnavascues/cde12f67ad2b9a1d256e260d19e8baae to your computer and use it in GitHub Desktop.
Save vnavascues/cde12f67ad2b9a1d256e260d19e8baae to your computer and use it in GitHub Desktop.
An AccuWeather Consumer contract
// 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