Skip to content

Conversation

@samthomson
Copy link

@samthomson samthomson commented Dec 17, 2025

DRAFT & WIP

I've started playing around with building weather stations. I will keep building / refining (with others - you?) the next months.
It makes sense to be to have one kind for the weather station and one kind for each weather station reading. (A list of weather stations eg I operate, could also be handy - put that doesn't need to be reinvented here).
Wisdom / collaboration is welcome, and appreciated 🙏
You can see some data being consumed here (from a proto kind): https://weather.shakespeare.wtf

@samthomson samthomson marked this pull request as draft December 17, 2025 18:40
@vitorpamplona
Copy link
Collaborator

Move the json in content to tags to get rid of yet another parser

@derekross
Copy link

i look forward to having weather stations all over the world. you should also link the PoC website.

@samthomson
Copy link
Author

thanks @vitorpamplona. I first thought to have everything in tags, but then thought I'd put some high level things in tags and then fine grained data in content/json. Do you think its ok to have potentially a whole bunch of tags?

@vitorpamplona
Copy link
Collaborator

Do you think its ok to have potentially a whole bunch of tags?

Yep. That's ok. We have events with over 5000 tags.

nip-weather.md Outdated
"kind": 23415,
"tags": [
["s", "<station-id>"],
["a", "16428:<pubkey>", "<relay-url>"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this a needs to have a second : 16428:<pubkey>:

nip-weather.md Outdated

### Event Kind Range for Readings

Currently `kind:23415` is ephemeral (20000-29999), meaning relays are not expected to store readings. Should readings use regular events (1000-9999) instead to enable historical data queries and trend analysis? Tradeoff: storage burden vs. historical value.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use a 30xxx event where the d tag is the station-id. In that way relays will always save the current temp (so people can check the temp right now) and those subscribed to the temp changes can save all the versions of the 30xxx event.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to query a relay and get all the weather data from the last hour or day though, which makes me think regular events (1000-9999) would be best. wdyt?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. If you need to get a collection of them, then regular events (potentially with an expiration tag) are better.

@alltheseas
Copy link
Contributor

why not: consider g tag/geohash for location, as defined in nip-52.

https://grokipedia.com/page/Geohash

@samthomson
Copy link
Author

@alltheseas good idea. Updated.

@alltheseas
Copy link
Contributor

A few more comments:

  1. I see kind-30001 - NIP-51.md calls this kind deprecated. Not sure what the right kind is. Maybe this is a new weather-station specific kind? You mention this can be sorted at the end, so that works.
  2. Since weather station/measurements are distinct/new kinds to all of nostr, NIP-31 alt tag could be useful to advise what this is.
  3. Add pressure - dont recall what the real world unit of measurement is (mb?)
  4. Add wind speed (kt/knots)
  5. Add wind direction (see https://windy.app/blog/what-is-wind-direction.html)
  6. add rain (in/mm)
  7. add waves - significant wave height (ft/m) and period (seconds)
  8. add wave direction (can use same approach as wind direction)
  9. dealing with broken/faulty sensors - what happens if a sensor fails? what's the notation for null/no data?
  10. timestamps - the happy path here is that the nostr JSON blob created at timestamp is also the timestamp for the observed data. An unhappy paths is that we have an offline weather station for whatever reason, which could mean that when back online the station publishes data observed at a different time and/or mass/batch submits stored / recorded data etc.

In a standard kind-1 note we have the following example: "created_at": 1766813498,
which per NIP-01 is defined as "created_at": <unix timestamp in seconds>.

So maybe we add a "observed_at": <unix timestamp in seconds> in the case of unhappy paths of JSON creation timestamp differing from met station observation timestamp.

@vitorpamplona
Copy link
Collaborator

Re NIP-51, you probably want to choose your own kind for this.

@alltheseas
Copy link
Contributor

On wave height - on second thought metocean sensors should be assumed to record, and share raw data. Therefore wave height should be just raw wave height, not significant wave height. Hs can be calculated after.

Copy link
Collaborator

@hzrd149 hzrd149 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know you didn't ask for a review, but I figured I would offer some feedback.

all-in-all I really like the idea and it would be cool to start seeing weather data show up on nostr relays

nip-weather.md Outdated
```

Tags:
- `t` (optional): Hashtag for discovery. SHOULD include `["t", "weather"]` for relay indexing.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the event kind is set in this nip then there shouldn't be need for a hashtag. clients should be able to just query for the event kind

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, it's redundant.

nip-weather.md Outdated

Tags:
- `t` (optional): Hashtag for discovery. SHOULD include `["t", "weather"]` for relay indexing.
- `a` (optional): Reference to the station metadata event (`10xxx:<pubkey>:` - note trailing colon for replaceable events). This links the reading to its station.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The station metadata event is a single replaceable event presumably signed by the same pubkey so I don't really see the point in including an a tag since it will always be easier to lookup the station metadata by the events author

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, obsolete.

- `air_quality`: Raw analog sensor value (0-1023, uncalibrated)
- Other sensor tags as needed

The third parameter (model) identifies the sensor model (e.g., "DHT11", "PMS5003", "MQ-135"), enabling:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to define if this string follows a specific format or is just generally human readable.
If its designed to be aggregated across stations then it would be good to have it standardized so there is as much interoperability as possible

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean like a const/enum of sensor types? ie allowed values only?

nip-weather.md Outdated

## Discovery

The `["t", "weather"]` hashtag is optional but recommended in reading events to enable relay indexing and discovery of weather stations. Clients can discover weather data by querying for `{"#t": ["weather"]}`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't really make sense to me, couldn't they just discover the sensor data by querying for the 4223 kind?

nip-weather.md Outdated
- `t` (optional): Hashtag for discovery. SHOULD include `["t", "weather"]` for relay indexing.
- Other tags as needed

To group multiple stations together, use [NIP-51](51.md) lists. `kind:30001` (generic lists) can be used with `p` tags referencing station pubkeys. Example:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure grouping stations needs to be part of this nip. I don't see any harm in it though

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, please see my response above to elsat and kindly share any thoughts you have.


Tags:
- `name` (optional): Human-readable station name
- `g` (optional): Geohash for location indexing (see [NIP-52](52.md))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember which nip it was defined in but it would be good to define if this is a single g tag or one g tag per geohash level

Including a g tag for each level makes it possible to easily lookup events by location with the current NIP-01 filters

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a bad idea, thanks

@samthomson
Copy link
Author

samthomson commented Jan 2, 2026

@alltheseas Thanks a lot for such a thorough set of thoughts.

1 - nip-51/kind-30001. I thought a way to group stations together could be handy. some usecases/context that come to mind: to see 'my' stations (each has its own private key so [author = me] isn't a fit), or all the stations in my town so that I can crunch pollution data over time that's relevant to me, or all the stations at a running route or across running routes so I can plan where to jog that day. Thoughts welcome on what could be best here. I thought 30001 as a 'custom list' type could save creating another type in nip-51 (but maybe adding more types isn't such a bad thing?). For now I'll placeholder a new 3**** custom set in nip-51.

2 - Good idea with the alt tag. Do you think just a 'Weather station data' or 'Weather station reading' is enough? I could make a literal 'Weather reading: 22.5°C, 65% humidity' otherwise, but I'm conscious that would - at one reading a minute - add up to a lot of data over time. Thoughts welcome.

3/6 - Rain/Pressure - on the list, thanks. I've added a table showing all sensors working / in progress.

4/5/7/8 - Added to the list, as proposed.

9 - I see two things here.
a)The reading event could for the failed sensor either not record that sensor, or it could record it with an intentional null value. I think omitting it makes most sense (in conjunction with b).
b) Separately the weather station could have either a 'broken' value on that sensor tag, or it could separatley have tags for 'sensor_status' or 'broken_sensor'. I think sensor_status could be best. ok, offline, error. maybe even 200, 400, 500 (or I'm overthinking).

10 - Very good point. Observed_at makes sense. I would guess the majority of the time created_at === observed_at, meanings lots of duplicate data. Do you think that's ok or we'd just add the observed_at to the event if publishing failed. or wdyt?

@samthomson
Copy link
Author

@hzrd149 thanks a lot for your review. very valuable. I have updated accordingly and will udpate my wip weather station code tonight.

@alltheseas
Copy link
Contributor

alltheseas commented Jan 2, 2026

@alltheseas Thanks a lot for such a thorough set of thoughts.

1 - maybe adding more types isn't such a bad thing?). For now I'll placeholder a new 3**** custom set in nip-51.

I think new kind(s) are fine. @arcbtc @BenGWeeks did y'all have some IOT related kinds at some point on nostr? @fiatjaf was your dishwasher npub just kind-1?

2 - Good idea with the alt tag. Do you think just a 'Weather station data' or 'Weather station reading' is enough?

Short and descriptive seems fine.

10 -Observed_at makes sense. I would guess the majority of the time created_at === observed_at, meanings lots of duplicate data. Do you think that's ok or we'd just add the observed_at to the event if publishing failed. or wdyt?
I would guess the majority of the time created_at === observed_at, meanings lots of duplicate data.

The timestamp a measurement was observed at is half of the measurement. Without the timestamp the measurement loses its' value.

It is necessary to have this separate from the nostr posting time.

Here we are ensuring that data recorded/submitted via unhappy paths remains valuable, and does not lose fidelity:

  1. e.g. solar powered node that goes down overnight, or for a few days if there is no sun,
  2. Internet/satellite/cell goes down,
  3. nostr relay(s) go down, not accepting data for whatever reason,
  4. weather node outbound comms, or other failure.

The more remote the weather station, the more exotic the destination and setup, the more resources & effort it takes to go and fix it, should it go down. If it can keep recording data while not being able to transmit it, and/or not lose data that has not been transmitted, this should reduce the station maintainer headaches by not losing crucial measurement data in time.

By virtue of the distinction between created_at and observed_at the station maintainer can also spot irregular patterns in node behavior, node transmittal behavior.

@BenGWeeks
Copy link

BenGWeeks commented Jan 2, 2026

@alltheseas Thanks a lot for such a thorough set of thoughts.
1 - maybe adding more types isn't such a bad thing?). For now I'll placeholder a new 3**** custom set in nip-51.

I think new kind(s) are fine. @arcbtc @BenGWeeks did y'all have some IOT related kinds at some point on nostr? @fiatjaf was your dishwasher npub just kind-1?

I haven't published any IoT-related kinds that I recall, but I did build a "Mars BioPod" project (LED grow lights + aquaponics with trout) that had air temperature sensors but most taken manually. They were constructed out of IBC containers wth soil-less grow beds and Nasa research derived LEDs (of wavelengths for photosynthesis). Before the days of Nostr though.I would have loved to also log:

  • pH
  • Water temperature
  • Dissolved oxygen
  • Ammonia/nitrite/nitrate levels

Basically the nitrogen cycle metrics you need for aquaponics.

I did just ditch my Netatmo weather station - yet another subscription service (and wanted something I could plug into Home Assist). Would be great to have a Nostr baed solution.

I also worked briefly with an agri company that were interested in various soil metrics (forget exactly which now) for farmers.

Looking at this draft, the tag-based approach (temperature, humidity, pressure) seems extensible enough to accommodate water quality sensors with the same pattern. Might be worth considering whether this could be Environmental Sensor Data rather than strictly Weather Station Data - or at least designed with that extensibility in mind for agricultural/aquaponics IoT use cases - although on the flip side you might want to differentiate between water temperature in a [controlled] fish tank, and the middle of the Atlantic).

@alltheseas
Copy link
Contributor

I am exploring iNaturalist inspired crowdsourced environmental reporting app. Draft plan builds partially off draft weather station NIP:

https://github.com/alltheseas/bluesky-observer

@samthomson
Copy link
Author

I am exploring iNaturalist inspired crowdsourced environmental reporting app. Draft plan builds partially off draft weather station NIP:

https://github.com/alltheseas/bluesky-observer

Very interesting indeed. Great stuff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants