{"id":21051561,"url":"https://github.com/pskinnertech/streamr-weather","last_synced_at":"2026-04-15T15:32:16.731Z","repository":{"id":233177073,"uuid":"669936127","full_name":"PSkinnerTech/streamr-weather","owner":"PSkinnerTech","description":"This project uses Next.js, Streamr, and Mapbox to visualize real-time weather data. It fetches live data from Streamr Network and plots it on a map. Features include temperature conversion, marker clustering, and a loading animation.","archived":false,"fork":false,"pushed_at":"2023-07-24T02:43:44.000Z","size":195,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-13T23:25:30.674Z","etag":null,"topics":["mapbox","mapbox-gl-js","nodejs","streamr","streamr-network","typescript","vercel"],"latest_commit_sha":null,"homepage":"https://streamr-weather.vercel.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PSkinnerTech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-07-23T22:59:58.000Z","updated_at":"2024-02-04T13:35:31.000Z","dependencies_parsed_at":"2024-04-14T10:36:54.749Z","dependency_job_id":"05dd9397-077f-4cc4-b5db-33278f891a93","html_url":"https://github.com/PSkinnerTech/streamr-weather","commit_stats":null,"previous_names":["pskinnertech/streamr-weather"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/PSkinnerTech/streamr-weather","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PSkinnerTech%2Fstreamr-weather","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PSkinnerTech%2Fstreamr-weather/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PSkinnerTech%2Fstreamr-weather/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PSkinnerTech%2Fstreamr-weather/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PSkinnerTech","download_url":"https://codeload.github.com/PSkinnerTech/streamr-weather/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PSkinnerTech%2Fstreamr-weather/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280742567,"owners_count":26382923,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-24T02:00:06.418Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mapbox","mapbox-gl-js","nodejs","streamr","streamr-network","typescript","vercel"],"created_at":"2024-11-19T15:58:15.420Z","updated_at":"2025-10-24T04:46:10.164Z","avatar_url":"https://github.com/PSkinnerTech.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Streamr Weather Data Visualization with Next.js and Mapbox\n\nThis project demonstrates how to use real-time weather data from the Streamr Network, visualize it as plot points on a Mapbox map, and limit the number of plot points to avoid overloading the browser. All of this is done using Next.js and TypeScript.\n\n## Tech Stack\n\nThis project uses a variety of technologies and libraries:\n\n- [Next.js](https://nextjs.org/): A React framework for building JavaScript applications.\n- [Streamr](https://www.streamr.network/): A decentralized platform for real-time data.\n- [Mapbox](https://www.mapbox.com/): An open-source mapping platform for custom designed maps.\n- [TypeScript](https://www.typescriptlang.org/): A statically typed superset of JavaScript that adds optional types.\n- [Tailwind CSS](https://tailwindcss.com/): A utility-first CSS framework for rapidly building custom user interfaces.\n- [React Loader Spinner](https://www.npmjs.com/package/react-loader-spinner): A customizable spinner component for loading state.\n\n## How It Works\n\n### Streamr Data\n\nThe application uses the Streamr client to subscribe to a real-time data stream. The data stream used in this project is a weather data stream from the Streamr Network. The data includes temperature, latitude, and longitude.\n\n### Mapbox Map\n\nThe application uses Mapbox to visualize the data. Each data point from the Streamr data stream is plotted on the map as a marker. When you click on a marker, a popup displays the temperature and coordinates of the data point.\n\n### Limiting Plot Points\n\nTo prevent the browser from being overloaded with plot points, the application limits the number of markers on the map to 100. When a new marker is added, the oldest marker is removed if there are already 100 markers on the map.\n\n### Next.js and TypeScript\n\nThe application is built with Next.js, a React framework, and TypeScript, a statically typed superset of JavaScript. These tools provide a robust and type-safe development environment.\n\n## Take the Repo for a Spin... Locally.\n\n1. Clone the repository: `git clone https://github.com/PSkinnerTech/streamr-weather.git`\n2. Install the dependencies: `npm install`\n3. Create a `.env` file in the root directory and add your Mapbox access token as `NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN=your_mapbox_access_token`\n4. Run the development server: `npm run dev`\n\n## Getting Started\n\n1. **Set up your development environment**\n\n   - Install [Node.js](https://nodejs.org/en/download/) and [npm](https://www.npmjs.com/get-npm) (comes with Node.js) on your machine.\n   - Install [Next.js](https://nextjs.org/docs/getting-started) by running `npx create-next-app@latest` in your terminal.\n\n2. **Create a new Next.js application**\n\n   - Run `npx create-next-app@latest streamr-weather` in your terminal to create a new Next.js application.\n   - Navigate to your new project directory with `cd streamr-weather`.\n\n3. **Install necessary packages**\n\n   - Install the necessary packages by running the following commands in your terminal:\n     - `npm install streamr-client`\n     - `npm install mapbox-gl`\n     - `npm install tailwindcss postcss autoprefixer`\n     - `npm install @types/mapbox-gl`\n     - `npm install typescript @types/react @types/node --save-dev`\n\n4. **Set up Tailwind CSS**\n\n   - Create a new `postcss.config.js` file in the root of your project and add the following code:\n\n     ```javascript\n     module.exports = {\n       plugins: {\n         tailwindcss: {},\n         autoprefixer: {},\n       },\n     };\n     ```\n\n   - Create a new `tailwind.config.js` file in the root of your project and add the following code:\n\n     ```javascript\n     module.exports = {\n       purge: [\"./src/**/*.{js,ts,jsx,tsx}\"],\n       darkMode: false, // or 'media' or 'class'\n       theme: {\n         extend: {},\n       },\n       variants: {\n         extend: {},\n       },\n       plugins: [],\n     };\n     ```\n\n   - In the `globals.css` file, import Tailwind's base, components, and utilities styles by adding the following code:\n\n     ```css\n     @import \"tailwindcss/base\";\n     @import \"tailwindcss/components\";\n     @import \"tailwindcss/utilities\";\n     ```\n\n5. **Folder Structure**\n\n   ```bash\n   /streamr-weather\n    ├── node_modules\n    ├── public\n    ├── src\n    │ ├── components\n    │ │ ├── MapComponents.tsx\n    │ ├── pages\n    │ │ ├── index.tsx\n    │ ├── StreamrClient.ts\n    ├── .env.local\n    ├── .gitignore\n    ├── package.json\n    ├── tsconfig.json\n    └── README.md\n   ```\n\n6. **Set up Mapbox**\n\n   - Sign up for a free account on [Mapbox](https://www.mapbox.com/) and get your access token.\n   - Create a new `.env` file in the root of your project and add the following code:\n\n     ```env\n     NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN=your_mapbox_access_token\n     ```\n\n   - Replace `your_mapbox_access_token` with your actual Mapbox access token.\n\n7. **Step 7: Set Up Streamr**\n\n   1. **Create a Streamr account:** Visit [Streamr](https://streamr.network/) and sign up for a new account if you don't have one already.\n   2. **Get the Stream ID:** For this project, we will be using a specific Stream ID: `streams.dimo.eth/firehose/weather`. This is the ID of the Stream that we will be subscribing to in order to receive the weather data.\n   3. **Generate a Private Key:** In order to authenticate with the Streamr API, we need a private key. For the purpose of this tutorial, we will generate a random private key using the `crypto` library. In a production environment, you would want to securely store and manage your private keys. Here's how you can generate a random private key:\n\n   ```typescript\n   const crypto = require(\"crypto\");\n   const privateKey = crypto.randomBytes(32).toString(\"hex\");\n   ```\n\n   4. **Update the .env.local file:** Open the `.env.local` file in your project and replace `YOUR_STREAMR_API_KEY` with the private key you just generated. Replace `YOUR_STREAM_ID` with the Stream ID `streams.dimo.eth/firehose/weather`.\n\n   ```typescript\n   NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN = YOUR_MAPBOX_ACCESS_TOKEN;\n   STREAMR_API_KEY = YOUR_PRIVATE_KEY;\n   STREAM_ID = streams.dimo.eth / firehose / weather;\n   ```\n\n   5. **Set up Streamr in the project:** In the `StreamrClient.ts` file, we're using the `require` function to import the `streamr-client` package. This is because, as of the time of writing this tutorial, the `streamr-client` package doesn't fully support ES6 imports. Therefore, we use `const StreamrClient = require(\"streamr-client\");` instead of `import { StreamrClient } from \"streamr-client\";`.\n\n   ```typescript\n   const StreamrClient = require(\"streamr-client\");\n\n   const client = new StreamrClient({\n     auth: {\n       privateKey: process.env.STREAMR_API_KEY,\n     },\n   });\n\n   const main = async (handleData: (data: any) =\u003e void) =\u003e {\n     await client.connect();\n\n     const subscription = await client.subscribe(\n       {\n         stream: process.env.STREAM_ID,\n       },\n       (message: any, metadata: any) =\u003e {\n         handleData(message);\n       }\n     );\n   };\n\n   export default main;\n   ```\n\n8. **Step 8: Set Up Mapbox**\n\n   1. **Create a Mapbox account:** Visit [Mapbox](https://www.mapbox.com/) and sign up for a new account if you don't have one already.\n   2. **Get the Mapbox Access Token:** Once you've created an account and logged in, navigate to your Account page. Here, you can create a new Access Token. Make sure to save this token somewhere safe, as you won't be able to view it again.\n   3. **Update the .env.local file:** Open the `.env.local` file in your project and replace `YOUR_MAPBOX_ACCESS_TOKEN` with the Access Token you just generated.\n\n   ```jsx\n   NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN = YOUR_MAPBOX_ACCESS_TOKEN;\n   STREAMR_API_KEY = YOUR_PRIVATE_KEY;\n   STREAM_ID = streams.dimo.eth / firehose / weather;\n   ```\n\n   4. **Set up Mapbox in the project:** In the `MapComponents.tsx` file, we're using the `require` function to import the `mapbox-gl` package. This is because, as of the time of writing this tutorial, the `mapbox-gl` package doesn't fully support ES6 imports. Therefore, we use `const mapboxgl = require(\"mapbox-gl/dist/mapbox-gl.js\");` instead of `import mapboxgl from \"mapbox-gl\";`.\n\n   ```typescript\n   import React, { useEffect, useRef } from \"react\";\n   const mapboxgl = require(\"mapbox-gl/dist/mapbox-gl.js\");\n   import \"mapbox-gl/dist/mapbox-gl.css\";\n\n   interface DataProps {\n     ambientTemp: number;\n     latitude: number;\n     longitude: number;\n   }\n\n   interface MapProps {\n     data: DataProps;\n   }\n\n   const celsiusToFahrenheit = (celsius: number) =\u003e (celsius * 9) / 5 + 32;\n\n   const MapComponent: React.FC\u003cMapProps\u003e = ({ data }) =\u003e {\n     const mapContainerRef = useRef\u003cHTMLDivElement | null\u003e(null);\n     const map = useRef\u003cmapboxgl.Map | null\u003e(null);\n\n     useEffect(() =\u003e {\n       mapboxgl.accessToken = process.env\n         .NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN as string;\n       map.current = new mapboxgl.Map({\n         container: mapContainerRef.current as HTMLElement,\n         style: \"mapbox://styles/mapbox/streets-v11\",\n         center: [data.longitude, data.latitude],\n         zoom: 2,\n       });\n\n       // cleanup function to remove map on unmount\n       return () =\u003e map.current?.remove();\n     }, []);\n\n     useEffect(() =\u003e {\n       if (data \u0026\u0026 map.current) {\n         const marker = new mapboxgl.Marker()\n           .setLngLat([data.longitude, data.latitude])\n           .addTo(map.current);\n\n         const popup = new mapboxgl.Popup({ offset: 25 }).setHTML(\n           `\u003ch3 style=\"color: black;\"\u003eWeather Data\u003c/h3\u003e\u003cp style=\"color: black;\"\u003eTemperature: ${\n             data.ambientTemp\n           }°C / ${celsiusToFahrenheit(data.ambientTemp).toFixed(\n             2\n           )}°F\u003cbr\u003eLatitude: ${data.latitude}\u003cbr\u003eLongitude: ${\n             data.longitude\n           }\u003c/p\u003e`\n         );\n\n         marker.setPopup(popup);\n       }\n     }, [data]);\n\n     return (\n       \u003cdiv ref={mapContainerRef} style={{ width: \"100%\", height: \"600px\" }} /\u003e\n     );\n   };\n\n   export default MapComponent;\n   ```\n\n9. **Step 9: Set Up the Data Stream**\n\n   1. **Create the StreamrClient.ts file:** In the `src` directory, create a new file named `StreamrClient.ts`. This file will be responsible for setting up the Streamr client and subscribing to the data stream.\n   2. **Set up the Streamr client:** In the `StreamrClient.ts` file, we're going to set up the Streamr client. We'll import the `StreamrClient` package using the `require` function, similar to how we imported the `mapbox-gl` package. This is because, as of the time of writing this tutorial, the `streamr-client` package doesn't fully support ES6 imports. Therefore, we use `const StreamrClient = require(\"streamr-client\");` instead of `import { StreamrClient } from \"streamr-client\";`.\n   3. **Subscribe to the data stream:** We'll use the `subscribe` method provided by the Streamr client to subscribe to the data stream. We'll pass in the `streamId` and a callback function that will be called every time a new message is received from the stream. The callback function will receive the message data as its argument.\n\n   ```typescript\n   const StreamrClient = require(\"streamr-client\");\n\n   const client = new StreamrClient({\n     auth: {\n       privateKey: process.env.STREAMR_API_KEY,\n     },\n   });\n\n   const main = async (handleData: (data: any) =\u003e void) =\u003e {\n     await client.connect();\n\n     const subscription = await client.subscribe(\n       {\n         stream: process.env.STREAM_ID,\n       },\n       (message: any, metadata: any) =\u003e {\n         handleData(message);\n       }\n     );\n   };\n\n   export default main;\n   ```\n\n10. **Step 10: Set Up the Main Page**\n\n    1. **Create the index.tsx file:** In the `src/pages` directory, create a new file named `index.tsx`. This file will be responsible for rendering the main page of the application.\n    2. **Import necessary packages and components:** At the top of the `index.tsx` file, import the necessary packages and components. This includes React, the `useEffect` and `useState` hooks from React, the `MapComponent` component, and the `main` function from the `StreamrClient.ts` file.\n    3. **Set up the main page component:** In the `index.tsx` file, set up the main page component. This component will use the `useState` hook to keep track of the current data from the Streamr data stream, and the `useEffect` hook to subscribe to the data stream when the component mounts.\n\n    ```typescript\n    import React, { useEffect, useState } from \"react\";\n    import MapComponent from \"../components/MapComponent\";\n    import main from \"../StreamrClient\";\n\n    const IndexPage: React.FC = () =\u003e {\n      const [data, setData] = useState(null);\n\n      useEffect(() =\u003e {\n        main((message: any) =\u003e {\n          setData(message);\n        });\n      }, []);\n\n      return (\n        \u003cdiv className=\"flex flex-col items-center justify-center min-h-screen py-2\"\u003e\n          \u003cdiv className=\"flex flex-col items-center justify-center\"\u003e\n            {data \u0026\u0026 \u003cMapComponent data={data} /\u003e}\n          \u003c/div\u003e\n        \u003c/div\u003e\n      );\n    };\n\n    export default IndexPage;\n    ```\n\n11. **Step 11: Run the Application**\n    1. **Start the development server:** After setting up the StreamrClient and Mapbox components, you can now run the application. In your terminal, run the command `npm run dev` to start the development server.\n    2. **Open the application in a browser:** Once the development server is running, open a web browser and navigate to `http://localhost:3000`. You should see the application running, with real-time weather data being fetched from the Streamr Network and plotted on the Mapbox map.\n    3. **Interact with the application:** Click on the markers on the map to view the temperature and coordinates data. The markers are clustered to improve performance and usability.\n\n## Conclusion\n\nCongratulations! You've successfully built a real-time weather data visualization application using Streamr, Mapbox, Next.js, and TypeScript. This application demonstrates the power of real-time data streams and how they can be used to provide up-to-date, dynamic content in a web application. Whether you're building a weather app, a live dashboard, or any other application that requires real-time data, Streamr provides a powerful, easy-to-use platform for working with real-time data streams.\n\n[TWITTER](https://twitter.com/PSkinnerTech)\n[GITHUB](https://github.com/PSkinnerTech)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpskinnertech%2Fstreamr-weather","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpskinnertech%2Fstreamr-weather","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpskinnertech%2Fstreamr-weather/lists"}