{"id":37689400,"url":"https://github.com/skhg/weather-station","last_synced_at":"2026-01-16T12:39:39.391Z","repository":{"id":49596390,"uuid":"256016790","full_name":"skhg/weather-station","owner":"skhg","description":"🌥 ESP8266-based personal weather station project","archived":false,"fork":false,"pushed_at":"2022-12-03T22:54:46.000Z","size":33459,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-15T00:16:10.012Z","etag":null,"topics":["air-quality","arduino","cpp","data","electronics","environment","esp8266","weather"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skhg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-15T19:28:50.000Z","updated_at":"2021-07-16T20:08:08.000Z","dependencies_parsed_at":"2022-08-22T14:50:45.839Z","dependency_job_id":null,"html_url":"https://github.com/skhg/weather-station","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/skhg/weather-station","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skhg%2Fweather-station","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skhg%2Fweather-station/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skhg%2Fweather-station/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skhg%2Fweather-station/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skhg","download_url":"https://codeload.github.com/skhg/weather-station/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skhg%2Fweather-station/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28478717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["air-quality","arduino","cpp","data","electronics","environment","esp8266","weather"],"created_at":"2026-01-16T12:39:38.722Z","updated_at":"2026-01-16T12:39:39.371Z","avatar_url":"https://github.com/skhg.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# weather-station\u003ca name=\"introduction\"\u003e\u003c/a\u003e\nI wanted to experiment with building environmental sensors, and see if I could make homemade electronics that would survive in the outdoors. So I built a weather station based around the Arduino-compatible ESP8266 platform.\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"images/station.gif\"/\u003e\u003cbr/\u003e\n\u003ci\u003eWeather station at work, in a light breeze. Most of the fun stuff is hidden inside that grey pipe.\u003c/i\u003e\n\u003c/p\u003e\n\n## Overview\nThere are many possible instruments that can be part of a weather station. For the amateur meteorologist, just a few are needed to make a start. They can all be bought cheaply online, and a weatherproof case can be made out of just a few short lengths of PVC piping. Credit to https://sensor.community for inspiration here - I based the system on this [reference design](https://sensor.community/en/sensors/airrohr/), with some additions for the extra sensors I wanted. The software is custom-made. See the [references](#references) section at the end for many useful links on how to build something similar yourself.\n\nWith this system we can measure:\n * Wind speed\n * Temperature\n * [Relative humidity](https://en.wikipedia.org/wiki/Relative_humidity)\n * [Air pressure](https://en.wikipedia.org/wiki/Atmospheric_pressure)\n * Air [particulate](https://en.wikipedia.org/wiki/Particulates) matter (PM2.5 and PM10)\n * Solar U.V. [intensity](https://en.wikipedia.org/wiki/Ultraviolet_index) - we can estimate the U.V. index\n * Rainfall (sort-of)\n \nThis is a wall-mounted device so wind direction wasn't really something I cared about for this project.\n\n## Materials required\n\nSensors and electronics:\n\n* [BME280](https://www.amazon.de/-/en/gp/product/B07D8T4HP6/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8\u0026psc=1) - Temperature, Humidity, and Air Pressure sensor\n* [SDS011](https://www.amazon.de/-/en/gp/product/B07911ZY9W/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8\u0026psc=1) - Air particulate matter sensor (PM2.5 and PM10)\n* [MH-RD](https://www.amazon.de/-/en/AZDelivery-Rain-Sensor-Module-Parent/dp/B07V5QQW9J/ref=sr_1_9?dchild=1\u0026keywords=arduino%2Bregensensor\u0026qid=1588014518\u0026sr=8-9\u0026th=1) - Rainfall droplet sensor\n* [Froggit](https://www.amazon.de/-/en/gp/product/B00GGM5HEA/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8\u0026psc=1) - Anemometer\n* [GY-8511](https://www.amazon.de/-/en/gp/product/B07PQPHJKR/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8\u0026psc=1) - Ultraviolet intensity sensor\n* [NodeMCU ESP8266](https://www.amazon.de/-/en/gp/product/B074Q2WM1Y/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8\u0026psc=1) - Arduino-compatible microcontroller\n* [JST headers](https://www.amazon.de/YIXISI-Connector-JST-XH-Female-Adapter/dp/B082ZLYRRN/ref=sr_1_1_sspa?dchild=1\u0026keywords=jst+kit\u0026qid=1605108398\u0026sr=8-1-spons\u0026psc=1\u0026spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUFITU9OODc2TFg4MzEmZW5jcnlwdGVkSWQ9QTAxNTU4NzMyOVdJRFVETUhCV1Y3JmVuY3J5cHRlZEFkSWQ9QTAwODA5ODVQWFZCU00yNTJBSlYmd2lkZ2V0TmFtZT1zcF9hdGYmYWN0aW9uPWNsaWNrUmVkaXJlY3QmZG9Ob3RMb2dDbGljaz10cnVl)\n* Digital/Analogue [multiplexer](https://www.amazon.de/-/en/gp/product/B06Y1L95GK/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8\u0026psc=1)\n* 10kΩ [resistor](https://www.amazon.de/-/en/gp/product/B07Q87JZ9G/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8\u0026psc=1)\n* [Ribbon cable](https://www.amazon.de/-/en/gp/product/B076CLY8NH/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8\u0026psc=1)\n* [Perfboard](https://www.amazon.de/-/en/gp/product/B07BDKG68Q/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8\u0026psc=1)\n* USB power supply\n\nCase construction:\n\n* 2x [45-degree drainpipe elbow](https://www.obi.de/ht-boegen/marley-ht-bogen-45-dn-75-grau/p/7436181)\n* [Drainpipe with \"cleaning\" cap](https://www.obi.de/ht-reinigungsrohre/marley-ht-reinigungsrohr-dn-75/p/7434681)\n* 2x [Gutter bracket](https://www.obi.de/kunststoff-dachrinnen/marley-rinnenhalter-verstellbar-dn-75-grau/p/5088869)\n* [PTFE tape](https://www.amazon.de/-/en/Pack-Sealing-Thread-Teflon-White/dp/B071X6PC89/ref=sr_1_5?dchild=1\u0026keywords=ptfe+tape\u0026qid=1605696229\u0026sr=8-5) for sealing joints\n* Wooden board for mounting as required\n* Rubber tube for air intake\n* Insulating plastic/foam liner\n\nUV Sensor module:\n* Some little [wooden boards](https://www.amazon.de/-/en/gp/product/B07D76MKFY/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8\u0026psc=1)\n* Small glass dome / [clock glass](https://www.amazon.de/-/en/gp/product/B00FWSFHBW/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8\u0026psc=1)\n* Weather-resistant cabling\n* Waterproof rubber gasket\n\n## Circuit\nThe NodeMCU connects directly to the digital devices, and uses a multiplexer to read from the analog output devices. This diagram represents the anemometer as a \"motor\" - it generates signal pulses as it rotates on an axis.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"images/weather-station_bb.png\"/\u003e\u003cbr/\u003e\n \u003ci\u003eCircuit overview - export from fritzing \u003ca href=\"weather-station.fzz\"\u003efile\u003c/a\u003e\u003c/i\u003e\u003c/p\u003e\n\nThe perfboard assembly was a little tricky because everything had to fit into a narrow package, and also be screwed on to the air quality board mounted directly underneath. This diagram shows how the two fit together. Those black squares on the perfboard show areas where holes were drilled to join the two together.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"images/weather-station-board_bb.png\"/\u003e\u003cbr/\u003e\n \u003ci\u003ePerfboard and external components - export from fritzing \u003ca href=\"weather-station-board.fzz\"\u003efile\u003c/a\u003e\u003c/i\u003e\u003c/p\u003e\n\nThe UV sensor is itself mounted on a small perfboard, which terminates the connection from the main case (It's mounted about 5m away and connected over Cat5 cable)\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"images/uv_sensor_mini_board_bb.png\"/\u003e\u003cbr/\u003e\n \u003ci\u003eUV sensor mini board - export from fritzing \u003ca href=\"uv_sensor_mini_board.fzz\"\u003efile\u003c/a\u003e\u003c/i\u003e\u003c/p\u003e\n\n## Assembly\n\nFirst step was to make sure all the components were working together. I had tested them [individually](/testing) beforehand. Here they're all mounted on a breadboard with external components wired in too.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"images/testing.jpeg\"/\u003e\u003c/p\u003e\n\nNext step was soldering the perfboard and mounting the multiplexer, NodeMCU and wiring. Followed by mounting the air quality sensor underneath - with a layer of plastic and foam in between to prevent any short-circuits between exposed pins on the two devices.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"images/board_only.jpeg\" width=\"50%\"/\u003e\u003cimg src=\"images/board_airqual_mounted.jpeg\" width=\"50%\"/\u003e\u003c/p\u003e\n\nAnd sliding the complete unit into the case:\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"images/sliding_into_tube.jpeg\" width=\"50%\"/\u003e\u003cimg src=\"images/installed_top.jpeg\" width=\"50%\"/\u003e\u003c/p\u003e\n\nIt's a tight fit!\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"images/tight_fit.jpeg\"/\u003e\u003c/p\u003e\n\nFor the external UV sensor, I made a flat mount on a piece of board and painted it white, to keep moisture out and keep it cool in the sunshine. The UV sensor is protected from moisture by:\n * A white cap from a jar of skin cream\n * A rubber gasket from a coffee mokka\n * An inverted clock glass (with relatively high UV-transmissivity)\n * Some plastic chair leg-ends to clamp it together with some flexibility\n \n\u003cp align=\"center\"\u003e\u003cimg src=\"images/uv_board_assembled.jpeg\" width=\"50%\"/\u003e\u003cimg src=\"images/uv_board_installed.jpeg\" width=\"50%\"/\u003e\u003c/p\u003e\n\n### Mounted in place\n\nWith everything in place and tightly fit together, it was time to install it in place on the balcony. We have a drainpipe that was a convenient place to attach it, as you can see in the \u003ca href=\"#introduction\"\u003eintroduction\u003c/a\u003e.\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"images/under.gif\"/\u003e\u003cbr/\u003e\n\u003ci\u003eView from underneath. Holes for external connections in the middle here.\u003c/i\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"images/tube_tempsensor.jpeg\" width=\"50%\"/\u003e\u003cimg src=\"images/tube_airsensor.jpeg\" width=\"50%\"/\u003e\u003cbr/\u003e\n\u003ci\u003eViews from the ends of either side of the main tube.\u003cbr/\u003eLeft: air intake tube and BME280 sensor. Right: rear of the SDS011 and exposed cabling.\u003c/i\u003e\n\u003c/p\u003e\n\n## Onboard software\nThe onboard [software](weather-station.ino) runs in a continuous loop. It captures the data, packages the results in a JSON blob, and sends them to a logging server on the local LAN. In case of any errors connecting to WiFi or to this server, it does a hard reboot. This is sufficient since the data is not time-critical, and up-to-date data is less important than an hourly/daily trend.\n\n\u003cimg src=\"images/cycle.svg\" width=\"50%\"/\u003e\u003cimg src=\"images/wind.svg\" width=\"30%\"/\u003e\u003cimg src=\"images/air.svg\" width=\"20%\"/\u003e\n\n## Data Capture and Visualisation\n\nReadings are packaged as a JSON blob and sent to a logging server on the local LAN, using a REST `POST` over HTTP. A sample message looks like:\n\n```json\n{\n    \"temperatureC\" : 21.2,\n    \"humidityPercentage\" : 34.2,\n    \"airPressurePa\" : 1001000.2,\n    \"uvIntensityMilliwattsPerCmSq\" : 3.2,\n    \"rainfallStrengthPercentage\" : 10.2,\n    \"pm25density\" : 10.1,\n    \"pm10density\" : 9.8,\n    \"windSpeedKmPerHour\" : 0.67\n}\n```\n\nThe logging server is a custom [Spring Boot](https://spring.io/projects/spring-boot) application. It logs the data to [InfluxDB](https://www.influxdata.com/), a time-series database. [Grafana](https://grafana.com/) is used for visualising the data.\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"images/data_24hr_sample.png\" width=\"48%\"/\u003e \u003cimg src=\"images/data_6month_sample.png\" width=\"48%\"/\u003e\u003cbr/\u003e\n\u003ci\u003eScreenshots of sample data from the Grafana dashboard.\u003cbr/\u003eLeft: 24 hours of data. Right: 6 months of data.\u003c/i\u003e\n\u003c/p\u003e\n\n## Performance over time\nIt survived its first summer with months of direct sunlight and internal temperatures up to 37°C. Will it survive its first winter, with ice and snow? Time will tell...\n\nAs of November 2020 it's been outside for over 6 months and still works, data seems consistent and matches what I see from the official weather reports. The only component that has significantly degraded is the rainfall sensor, which gives junk results now. Constant rainfall has eroded the resistive surface and left some kind of rust all over it. This should be replaced.\n\n## Future enhancements\n\nRainfall sensor:\n * Replace with a better device that will not degrade so much over time. A capacitive option might be a good alternative with no moving parts.\n \nRemove multiplexer:\n * I think I had some issues with analogue data reads the first time around, but it appears that the multiplexer board isn't actually required. I would remove this next time and connect external devices directly to the NodeMCU board.\n \nSubmit data online:\n * I would like to submit the recorded data from my server to https://luftdaten.info/, https://www.pwsweather.com/ or similar\n\nData validation:\n * The onboard software does no sanity checking of the data it reports back to the server. On at least one occasion this meant it reported a temperature of -143°C which was fixed by a hard reboot.\n * The software should include some hardcoded bounds outside which it will report an error status back to the server.\n\nCase construction:\n * The anemometer is mounted into a hole drilled in the pipe cleaning cap. Next time I would rather mount the anemometer into a bracket that clips on top of that cap. Having a hole that has to be sealed with PTFE, right above the electronics, is likely to eventually fail due to water accumulation.\n * All the external connectors (USB power in, rainfall sensor, UV sensor, and anemometer cable) are routed through holes drilled in the bottom of the case. This doesn't look great, and makes it awkward/imposssible to disconnect them without disassembling the whole thing.\n * I would like to build a small \"[patch panel](https://en.wikipedia.org/wiki/Patch_panel)\" with JST connectors for all the external connections, that would be flat-mounted on the bottom of the case. A single USB connection for power/data would also be located here, so everything could be disconnected as needed without needing to open the whole thing up.\n\nAir intake tube mount:\n * A 3D-printed mount for the air intake tube, [like this one](https://www.thingiverse.com/thing:3945004), would make the case look nicer and more professionally finished.\n\n## References\u003ca name=\"references\"\u003e\u003c/a\u003e\n* https://hackaday.io/project/165061-solar-powered-wifi-weather-station-v20#j-discussions-title - A solar-powered weather station combining several of the same sensors used here.\n* https://www.geeky-gadgets.com/arduino-wind-speed-meter-anemometer-project-30032016/ - Converting an anemometer's analogue readings into a digital signal for wind speed\n* https://learn.sparkfun.com/tutorials/ml8511-uv-sensor-hookup-guide/all - Using a UV intensity sensor\n* https://gist.github.com/geoffwatts/b0b488b5a5257223ed53 - Using a PM2.5 air particulate sensor\n* https://sensor.community/en/sensors/ - Reference designs for weather stations which I used as inspiration for this project\n* https://sensor.community/en/sensors/airrohr/ - The specific example I based this project on\n* https://learn.pimoroni.com/tutorial/sandyj/enviro-plus-and-luftdaten-air-quality-station - A similar project although based around the Raspberry Pi Zero platform\n* https://www.aeq-web.com/anemometer-mit-dem-arduino-bauen/ - Reading from an anemometer using an Arduino Uno\n* https://forum.arduino.cc/index.php?topic=616264.0 - Handling interrupts on a NodeMCU board\n* https://github.com/Naesstrom/Airrohr-kit - A similar project using a PCB\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskhg%2Fweather-station","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskhg%2Fweather-station","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskhg%2Fweather-station/lists"}