# City Weather on Chainlink Functions

### Remix

Go to Remix and create a new Solidity file by 1. going to the “FILE EXPLORER” and 2. clicking the “Create new file” icon:

<div align="left"><figure><img src="/files/nkat1CCxZ5gdaJPqMfp5" alt=""><figcaption><p>Create a new Solidity file</p></figcaption></figure></div>

Name the new file `WeatherFunctions.sol`:

<figure><img src="/files/1HK2UySoWG9cHTWWWIof" alt=""><figcaption><p>Create a new Solidity file</p></figcaption></figure>

The code is available at [GitHub](https://github.com/solangegueiros/chainlink-bootcamp-2024/blob/main/WeatherFunctions.sol) and also below:

{% code title="WeatherFunctions.sol" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

// Deploy on Fuji

import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/dev/v1_0_0/FunctionsClient.sol";
import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/dev/v1_0_0/libraries/FunctionsRequest.sol";

contract WeatherFunctions is FunctionsClient {
    using FunctionsRequest for FunctionsRequest.Request;

    // State variables to store the last request ID, response, and error
    bytes32 public lastRequestId;
    bytes public lastResponse;
    bytes public lastError;

    struct RequestStatus {
        bool fulfilled; // whether the request has been successfully fulfilled
        bool exists; // whether a requestId exists
        bytes response;
        bytes err;
    }
    mapping(bytes32 => RequestStatus) public requests; /* requestId --> requestStatus */          
    bytes32[] public requestIds;

    // Event to log responses
    event Response(
        bytes32 indexed requestId,
        string temperature,
        bytes response,
        bytes err
    );

    // Hardcoded for Fuji
    // Supported networks https://docs.chain.link/chainlink-functions/supported-networks
    address router = 0xA9d587a00A31A52Ed70D6026794a8FC5E2F5dCb0;
    bytes32 donID =
        0x66756e2d6176616c616e6368652d66756a692d31000000000000000000000000;

    //Callback gas limit
    uint32 gasLimit = 300000;

    // Your subscription ID.
    uint64 public subscriptionId;

    // JavaScript source code
    string public source =
        "const city = args[0];"
        "const apiResponse = await Functions.makeHttpRequest({"
        "url: `https://wttr.in/${city}?format=3&m`,"
        "responseType: 'text'"
        "});"
        "if (apiResponse.error) {"
        "throw Error('Request failed');"
        "}"
        "const { data } = apiResponse;"
        "return Functions.encodeString(data);";
    string public lastCity;    
    string public lastTemperature;
    address public lastSender;

    struct CityStruct {
        address sender;
        uint timestamp;
        string name;
        string temperature;
    }
    CityStruct[] public cities;
    mapping(string => uint256) public cityIndex;
    mapping(bytes32 => string) public request_city; /* requestId --> city*/

    constructor(uint64 functionsSubscriptionId) FunctionsClient(router) {
        subscriptionId = functionsSubscriptionId;      
    }

    function getTemperature(
        string memory _city
    ) external returns (bytes32 requestId) {

        string[] memory args = new string[](1);
        args[0] = _city;

        FunctionsRequest.Request memory req;
        req.initializeRequestForInlineJavaScript(source); // Initialize the request with JS code
        if (args.length > 0) req.setArgs(args); // Set the arguments for the request

        // Send the request and store the request ID
        lastRequestId = _sendRequest(
            req.encodeCBOR(),
            subscriptionId,
            gasLimit,
            donID
        );
        lastCity = _city;
        request_city[lastRequestId] = _city;

        CityStruct memory auxCityStruct = CityStruct({
            sender: msg.sender,
            timestamp: 0,
            name: _city,
            temperature: ""            
        });
        cities.push(auxCityStruct);
        cityIndex[_city] = cities.length-1;

        requests[lastRequestId] = RequestStatus({
            exists: true,
            fulfilled: false,
            response: "",
            err: ""
        });
        requestIds.push(lastRequestId);

        return lastRequestId;
    }

    // Receive the weather in the city requested
    function fulfillRequest(
        bytes32 requestId,
        bytes memory response,
        bytes memory err
    ) internal override {
        require(requests[requestId].exists, "request not found");

        lastError = err;
        lastResponse = response;

        requests[requestId].fulfilled = true;
        requests[requestId].response = response;
        requests[requestId].err = err;

        string memory auxCity = request_city[requestId];
        lastTemperature = string(response);
        cities[cityIndex[auxCity]].temperature = lastTemperature;
        cities[cityIndex[auxCity]].timestamp = block.timestamp;

        // Emit an event to log the response
        emit Response(requestId, lastTemperature, lastResponse, lastError);
    }

	function getCity(string memory city) public view returns (CityStruct memory) {
    	return cities[cityIndex[city]];
	}

	function listAllCities() public view returns (CityStruct[] memory) {
    	return cities;
	}

    function listCities(uint start, uint end) public view returns (CityStruct[] memory) {
        if (end > cities.length)
            end = cities.length-1;
        require (start <= end, "start must <= end");
        uint cityCount = end - start + 1;
        CityStruct[] memory citiesAux = new CityStruct[](cityCount);

        for (uint i = start; i < (end + 1); i++) {
            citiesAux[i-start] = cities[i];
        }
        return citiesAux;
    }

}
```

{% endcode %}

As in the previous exercise, in the “DEPLOY & RUN TRANSACTIONS”, make sure your “ENVIRONMENT is on “Injected Provider - Metamask” and you are on Avalanche Fuji Testnet 43113:

<div align="left"><figure><img src="/files/Qzr3Xqs4HP8WHvhQT58L" alt=""><figcaption></figcaption></figure></div>

Under the “DEPLOY” section, 1. paste in your Subscription ID we set up in the previous exercise and then 2. click the “transact” button to deploy our contract:

<figure><img src="/files/SRr8WvHkTw5GUdeaR2Hb" alt=""><figcaption><p>Enter your Chainlink Subscription ID and click "transact"</p></figcaption></figure>

MetaMask will once again pop-up and ask you to confirm the transaction:

<div align="left"><figure><img src="/files/AU6UPI6TT7IGjC1ccc7l" alt=""><figcaption><p>Confirm the transaction</p></figcaption></figure></div>

Once deployed, we need to add this contract's address as a consumer. Copy the contracts address from here in Remix:

<div align="left"><figure><img src="/files/hPNJcN2TeLD879yMYbdg" alt=""><figcaption><p>Copy your contract's address</p></figcaption></figure></div>

***

### You Subscription on Chainlink Functions

Navigate back to [Chainlink Functions](https://functions.chain.link/) and click the "Add consumer" button on the far right:

{% hint style="info" %}
You can have multiple consumer contracts in a single Chainlink Functions Subscription (up to 100)

[Chainlink Functions Service Limits](https://docs.chain.link/chainlink-functions/resources/service-limits)
{% endhint %}

<figure><img src="/files/5CXy6KrdxN7x05sCtdj0" alt=""><figcaption><p>Time to add a consumer</p></figcaption></figure>

Now 1. paste in your `WeatherFunctions.sol` deployed address and then 2. click the “Add consumer” blue button:

<figure><img src="/files/awvRkLJv4KKbQ1tuHo2g" alt=""><figcaption><p>Paste in your consumer address and add the consumer</p></figcaption></figure>

MetaMask will pop-up for you to confirm the transaction:

<figure><img src="/files/u0pKrodAuJCGRmevuyql" alt=""><figcaption><p>Confirm the transaction</p></figcaption></figure>

Once the transaction is confirmed, refresh the page you will now see your new consumer:

<figure><img src="/files/Q6AKuynBsZsxrd5RxJ7Z" alt=""><figcaption><p>Successfully added another consumer to your subscription</p></figcaption></figure>

Back in Remix with our deployed contract `WeatherFunctions.sol`, click the drop down arrow next to `getTemperature`:

<div align="left"><figure><img src="/files/PbatO2iM026BKllyMSFF" alt=""><figcaption><p>Click the down arrow</p></figcaption></figure></div>

Fill in the 1. `_city` argument as London, or maybe your next vacation city, and then 2. click the “transact” button and 3. MetaMask will pop-up asking you to “Confirm” the transaction:

<figure><img src="/files/fJ055wnszeVMAYQyz5Dk" alt=""><figcaption><p>Confirm the transaction</p></figcaption></figure>

After the transaction is complete, there are several read functions that will return you information. You asked for the weather in London, thus the `lastTemperature` function is what you are looking for below:

<div align="left"><figure><img src="/files/pqXkT4zGiC959ksjbP4I" alt=""><figcaption><p>You get London's weather!</p></figcaption></figure></div>

You can try any other city again.  Sao Paulo is the argument for `_city` (#1) and thus you would do another transaction and after completion, you now see the weather in Sao Paulo (#2)! \
\
&#x20;Click on the `listAllCities` function (#3), which returns a tuple of the history of what cities you have called for the current weather and it shows London and Sao Paulo:

<div align="left"><figure><img src="/files/JOnel0iuqlS03IVVGCAp" alt=""><figcaption><p>Weather in Sao Paulo and our history</p></figcaption></figure></div>

***

Here are more resources to help you with examples and guides to get a solid expert foundation on using Chainlink functions:

* [11 Ways To Use Chainlink Functions in Your Decentralized Applications](https://blog.chain.link/ways-to-use-chainlink-functions/)
* [Chainlink Dev Hub | Functions resources](https://dev.chain.link/products/functions)
* [Deep Dive Into Chainlink Functions | Constellation](https://www.youtube.com/watch?v=vt0OuOm4-aY)
* [useChainlinkFunctions()](https://usechainlinkfunctions.com/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://cll-devrel.gitbook.io/bootcamp-2024/9.-off-chain-data-with-chainlink-functions/city-weather-on-chainlink-functions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
