Hey there! My co-authors and I actually wrote a book on this topic earlier this year. It walks you though setting up a weather station with Elixir and Nerves using a Raspberry Pi and the following sensors:
After you set up the hardware side of things, you put together a very simple Elixir Phoenix REST API and persist the sensor data into Postgres (with the TimescaleDB extension).
And to wrap up the book, you learn how to create Grafana dashboards to visualize all your time-series data.
Everything is meant to be set up on your LAN and everything can be run either natively or in Docker (there is a Docker compose file in the repo).
Since OP mentioned not wanting to DIY, if people are looking for weather system with incredibly rich API and no moving parts (no Raspberry PIs either), this system is fantastic for people without workshop build time:
To clarify, the OP said: "I have neither time nor workshop space to solder and assemble anything more trivial than "plug a sensor into an ESP32 and screw both into a box"."
The book is very much "plug in a sensor" style as everything is connected via Qwiic cables.
That looks like it doesn't have any local-first functionality? Their API documentation only talks about how to retrieve data from their server, even if you are just trying to get the data from your own station.
Does it? I couldn't find any documentation on those features, if you have links to any documentation that doesn't require going through their servers I'd love to see it since I've been looking for something just like that. Everything I have found, even for querying a single devices, requires making a request to swd.weatherflow.com via an internet connection.
True. That said, it's still interesting to me, because an outdoor weather station is something I've also been eyeing, and also having trouble to find something that a) logs data, but b) not to a cloud.
It's not capable of CO2 measurement, it only estimates CO2 levels based on measurements of VOCs. These estimated readings are garbage and have close to zero correlation with CO2 levels.
Unless I've got another source of VOCs around there should be at least some correlation with actual CO2 levels though? I don't have a reliable way of checking this, but the bottom end seemed well calibrated...outside air leads to a reading consistent with ambient co2
We tested a lot of VOC sensor modules and the estimated CO2 values they give is -in our experience- 80% of the time totally wrong. Also the absolute ppb values of the TVOC are most often not to be trusted.
What they are good at is detecting spikes, e.g. from cleaning liquids, desinfection etc. but I would not trust the absolute value at all.
The big sensor manufacturers recognized that and newer generations of the Sensirion sensors are now just displaying an "index" instead of absolute measurements.
Thank you for asking this question because all of my experience so far with "environmental sensors" that aren't laboratory grade has been that they are absolute garbage and only barely correlated to anything.
How are companies like Bosch allowed to pass this crap off as functional? They don't meet even basic fitness for purpose criteria.
When developing the book, I didn't have any additional meters or sensors to cross reference measurements with so I can't comment on the accuracy unfortunately. But I did notice that the changes in measurements made sense when the environment changed. I.e when I would exhale on the sensor, the measurement would rise and fall.
Yeah same - there is definitely a practical cause & effect practical correlation, but also a lot of effect without obvious cause in an environment that should be relatively stable. (one person, small apt, no co2 sources)
> additional meters or sensors
I've got a CCS811 as well but no luck yet. Acquired 2nd hand so unsure if broken from shipping or I'm being stupid with code or I broke it while soldering
This reminds me how my DIY build of Luftdaten kit (PM sensor) started reporting huge particulate spikes indoors, with no obvious cause. Took me ~2 days to figure out they're being caused by our ultrasonic humidifier, and another 2 days of looking through blogs and scientific papers to finally learn that one shouldn't be putting tap water into them (as they efficiently aerosolise the minerals and contaminants dissolved in it).
Both the SGP30 and the BME680 have a big weakness that I experienced some years ago when I trying putting an air quality sensor together. They correlated the TVOC readings with the temperature. And sometimes it was bad, like a difference of just 1 or 2 degrees Celsius could double or triple the TVOC readings at the lower end of the scale (~50ppb), and add maybe ~50% at the upper end (~500ppb).
Really appreciate the kind words and happy to hear that you are enjoying the book! Hugo Baraúna and I have really enjoyed putting this book together and feel that Livebook has become pivotal in explaining certain topics and really understanding how things work under the hood. I wrote a blog post about some of my thoughts around Livebook as a learning tool on the DashBit blog: https://dashbit.co/blog/livebook-as-an-educational-tool
I have been using LiveView for over a year now in production applications, and I must say...it has been a breath of fresh air when developing web applications. The amount of product that you can deliver per unit time is unmatchable (in my opinion of course). The ceiling for what you can accomplish with a single tech stack (Elixir in this case) has definitely been lifted considerably.
Demo applications such as this show exactly what is possible in this tech stack and should make you question whether you need to make that leap to an SPA. At some point you will possibly need to lean on an SPA tool like Vue or React, but I think that point is now further away with tools like LiveView (Elixir), Hotwire (Ruby), and Livewire (PHP).
For a lot of the LiveView applications that I write (which is actually quite a few these days), I will usually lean on something like AlpineJS for frontend specific interactions, and my LiveView state is for things that require backend state.
For example, if I have a flag to show/hide a modal to confirm a resource delete, the show/hide flag would live in AlpineJS, while the resource I was deleting would live in the state of my LiveView.
This way, there are no round trips to the server over websocket to toggle the modal. Hopefully that example makes sense :).
The PHP equivalent would be the TALL stack (Tailwind, AlpineJS, Laravel and Livewire). Although Livewire just communicates over AJAX. The original Websockets version didn't make it.
I just found out that Livewire was inspired by LiveView.
I personally don't miss statically typed languages having worked professionally with Java, C++, and Typescript in the past. But if static typing is your cup of tea and you want to run on the BEAM, be sure to check out the Gleam programming language https://gleam.run/
In my day to day work I don't write many GenServers either and I think that's a good thing. Like any tool, they can be overused and abused. It is best to stick to modules and pure functions until you really need to pull the stateful lever.
To that point, GenServers as an abstraction are super powerful and when applicable, are an amazing tool. For example, being able to control the initialization of a supervision trees using :ignore in the init callback can be handy to run DB migrations as part of the application startup. Or when used in combination with a registry it can be useful to hold on to user data in a GenServer and access it atomically across your cluster.
Author here. Glad you like the banner image and the zooming effect :).
Perhaps I miscommunicated what I took away from the StackOverflow survey. The point that I was trying to make was that in relation to other programming languages in the survey, Elixir ranked high with regards to how loved it is. The StackOverflow survey is just one data point in addition to the others that I bring up and like many surveys has it's own issues (like WebAssembly being a compilation target as opposed to a programming language the people program in).
That standalone HTTP server in PromEx can also be used to expose metrics in non-Phoenix applications. In the coming weeks you'll also be able to run GrafanaAgent in the PromEx supervision tree so you can push Prometheus metrics via remote_write. Stay tuned ;)!
Excellent, looking forward to it! Right now I run GrafanaAgent separately which isn't too much headache and it works great feeding grafana cloud (especially paired with the Loki docker log driver).
As someone who has been programming with Elixir for my day job for the past few years, I find this aspect of the language to be super pragmatic and productive. It's a nice feeling to not have to chase new language features and syntax and focus more on the problem at hand. In addition, I've never felt limited by the language given that the underlying constructs are so powerful (message passing, immutability, pattern matching, etc). Glad that Jose made the decision that he did.
Curious, do you use typespecs and dialyzer? If so, how do you find it?
Elixir checks pretty much every box I'd want in a language, but after dealing with nil in Ruby for years and having fun with TypeScript... I'm feeling more drawn to working with type systems.
I find working with nil in Elixir to be quite reasonable. One way in which elixir is different is that you have different operators for when it must be boolean, and nil is not tolerated for those operators (and vs &&). This coupled with the convention of using ? at the end of functions which emit boolean makes things easier.
The one thing I wish is that people stopped writing boolean functions with is_ in front (that is supposed to be only for guards, but not everyone follows that convention).
If you want type systems, you can probably work with Gleam, in the future, I imagine there could be great interop where you can just drop in a .gleam file in your elixir code base with zero hassle attached, and have parts of your code base that are completely type safe, and let Elixir handle all the risks of IO and other effects.
I'm not a huge fan of Dialyzer myself. I would put it strongly in the "much better than nothing" category rather than the "usable and useful type system" category. I always write specs for my functions and types, and while they sometimes catch bugs, they're not quite as expressive as I would like them to be.
I suppose you could write Elixir in a style that was more type safe by writing in a less polymorphic or recursive style, but the language does not lend itself well to it. Structs and maps are mostly fine, discriminated unions less so.
Answering from similar experience. I personally use them both, dialyzer as part of the Elixir Language Server and typespecs when I feel something needs more clarity and definition.
Depending on what itches your types scratch for you it might be enough, might not. I've never wanted more type system in my Elixir personally.
I generally verify types only at the boundaries of my application (or very critical modules) using norm[1].
Either you have a strict type system that does not have an "any" type (yes, I'm looking at you Typescript), or you have a flexible type system like Python/Erlang/Elixir and you do runtime type checking whenever it's needed.
I'm writing more Typescript code than I would in Javascript for almost no type safety benefits (but for documentation, it's awesome).
Dialyzer and typespecs are better than nothing but not with much because they can introduce a lot of friction along the way, for not much benefit.
As another poster said, it can catch the very occasional potential bug but to me at least it's rarely worth the hassle.
I miss static typing after I got back to Elixir from Rust but the BEAM will likely never be statically typed.
To that end, I found utilizing metaprogramming to generate normal and property tests to be much more productive use of my time, with a measurable impact to boot.
Testing with the database has to be one of the things I love the most about Ecto. No need to mock anything, no need to have special branching logic for test versus prod. Just use the database like you normally do. It gives you a degree of confidence that is on another level. Check out https://hexdocs.pm/ecto_sql/Ecto.Adapters.SQL.Sandbox.html for more info!
Testing with the database isn't particularly efficient. If you have enough tests, it becomes worth it to mock whatever would touch the database just so the tests pass in a reasonable amount of time.
> Testing with the database isn't particularly efficient.
Anecdata, but my experience with Ecto sandbox + thousands of tests says otherwise. Mocking would be faster? Probably. But IMO not worth the effort, given it's already fast enough.
To be fair, I have worked with Elixir codebases that generated humongous amount of data per-test, only to test a fraction of this data. This kind of test was slow, but it would be much more efficient to generate only the data you actually need.
- VEML6030 light sensor - BME680 environmental sensor - SGP30 air quality sensor
After you set up the hardware side of things, you put together a very simple Elixir Phoenix REST API and persist the sensor data into Postgres (with the TimescaleDB extension).
And to wrap up the book, you learn how to create Grafana dashboards to visualize all your time-series data.
Everything is meant to be set up on your LAN and everything can be run either natively or in Docker (there is a Docker compose file in the repo).
Hope that helps!
GitHub Repo: https://github.com/akoutmos/nerves_weather_station Book: https://pragprog.com/titles/passweather/build-a-weather-stat...