We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Post 65
Weather App 12 - Publishing Sensor Data 01
Published on: 2025-08-27
Tags:
elixir, Generators , Blog, Side Project, Phoenix, Nerves, Weather App, Poncho
Chapter 4 Publishing Sensor Data (47)
Adding PostgreSQL to the Stack
Starting off we need to create a new phoenix weather_tracker app we will use the command
mix phx.new weather_tracker \
--binary-id --no-webpack --no-html --no-gettext --no-dashboard
With this being said you will need to have the right generator installed so if that doesn't work be sure to run this command within you linux console
mix archive.install hex phx_new 1.5.8
Once that is all setup we need to created the yml file and get into the proper location
cd weather_tracker && touch docker-compose.yml
Okay so now we can populate the file with
version: '3.3'
services:
postgres:
image: timescale/timescaledb:2.1.0-pg13
ports:
- '5432:5432'
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
volumes:
postgres-data: {}
Starting the Docker Compose Stack
docker-compose up
With that we will have the docker container up and running we will need to do some work to it so leave it up if you need to close it you can just crtl+calculated
Creating the Phoenix Application
We will need to run some migrations so that we can persist the data from the sensors
mix ecto.gen.migration set_up_weather_data_table
We can now setup the migrations for that data table with the following. It should have created a file with a time stamp and the file name appended to the time stamp.
defmodule WeatherTracker.Repo.Migrations.SetUpWeatherDataTable do
use Ecto.Migration
def up do
execute("CREATE EXTENSION IF NOT EXISTS timescaledb")
create table(:weather_conditions, primary_key: false) do
add :timestamp, :naive_datetime, null: false
add :temperature_c, :decimal, null: false
add :pressure_pa, :decimal, null: false
add :humidity_rh, :decimal, null: false
add :light_lumens, :decimal, null: false
add :voc_index, :decimal, null: false
add :uv_index, :decimal, null: false
add :als_lux, :decimal, null: false
end
execute("SELECT create_hypertable('weather_conditions', 'timestamp')")
end
def down do
drop table(:weather_conditions)
execute("DROP EXTENSION IF EXISTS timescaledb")
end
end
This will setup the data table with the correct :atoms as names and will say what to do when we rool forward or what happens when we want to roll the database backwards. This will also make sure that we are running the timescale DB as the data table type.
mix ecto.setup
This is where I ran into issues with the timescale not being installed so I went to this website and then followed all the instructions
https://docs.tigerdata.com/self-hosted/latest/install/installation-linux/
Creating our Ecto Schema
Now we need to set the way in which we add the correct values to the database. It will be in and called:
sensor_hub_poncho/weather_tracker/lib/weather_tracker/weather_conditions/weather_condition.ex
defmodule WeatherTracker.WeatherConditions.WeatherCondition do
use Ecto.Schema
import Ecto.Changeset
@allowed_fields [
:temperature_c,
:pressure_pa,
:humidity_rh,
:light_lumens,
:voc_index,
:uv_index,
:als_lux
]
@derive {Jason.Encoder, only: @allowed_fields}
@primary_key false
schema "weather_conditions" do
field :timestamp, :naive_datetime
field :temperature_c, :decimal
field :pressure_pa, :decimal
field :humidity_rh, :decimal
field :light_lumens, :decimal
field :voc_index, :decimal
field :uv_index, :decimal
field :als_lux, :decimal
end
def create_changset(weather_condition = %__MODULE__{}, attrs) do
timestamp =
NaiveDateTime.utc_now()
|> NaiveDateTime.truncate(:second)
weather_condition
|> cast(attrs, @allowed_fields)
|> validate_required(@allowed_fields)
|> put_change(:timestamp, timestamp)
end
end
Creating the Phoenix Context Module
Now we need the commands and code to instert any data to the database. This will be at: lib/weather_tracker/weather_conditions.ex and will be very simple as we don't need much from it.
defmodule WeatherTracker.WeatherConditions do
alias WeatherTracker.{WeatherConditions.WeatherCondition, Repo}
def create_weather_condition(attrs) do
%WeatherCondition{}
|> WeatherCondition.create_changeset(attrs)
|> Repo.insert()
end
end