library for veml6075
parent
07a44d3ff0
commit
5459f0f9e3
|
@ -0,0 +1,3 @@
|
|||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
|
@ -0,0 +1,27 @@
|
|||
# The directory Mix will write compiled artifacts to.
|
||||
/_build/
|
||||
|
||||
# If you run "mix test --cover", coverage assets end up here.
|
||||
/cover/
|
||||
|
||||
# The directory Mix downloads your dependencies sources to.
|
||||
/deps/
|
||||
|
||||
# Where third-party dependencies like ExDoc output generated docs.
|
||||
/doc/
|
||||
|
||||
# Ignore .fetch files in case you like to edit your project deps locally.
|
||||
/.fetch
|
||||
|
||||
# If the VM crashes, it generates a dump, let's ignore it too.
|
||||
erl_crash.dump
|
||||
|
||||
# Also ignore archive artifacts (built via "mix archive.build").
|
||||
*.ez
|
||||
|
||||
# Ignore package tarball (built via "mix hex.build").
|
||||
veml6075-*.tar
|
||||
|
||||
|
||||
# Temporary files for e.g. tests
|
||||
/tmp
|
|
@ -0,0 +1,21 @@
|
|||
# Veml6075
|
||||
|
||||
**TODO: Add description**
|
||||
|
||||
## Installation
|
||||
|
||||
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
|
||||
by adding `veml6075` to your list of dependencies in `mix.exs`:
|
||||
|
||||
```elixir
|
||||
def deps do
|
||||
[
|
||||
{:veml6075, "~> 0.1.0"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
||||
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
|
||||
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
|
||||
be found at <https://hexdocs.pm/veml6075>.
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
defmodule VEML6075 do
|
||||
use GenServer
|
||||
|
||||
require Logger
|
||||
|
||||
alias VEML6075.{Comm, Config}
|
||||
|
||||
def start_link(options \\ %{}) do
|
||||
GenServer.start_link(__MODULE__, options, name: __MODULE__)
|
||||
end
|
||||
|
||||
def get_measurement do
|
||||
GenServer.call(__MODULE__, :get_measurement)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(%{address: address, i2c_bus_name: bus_name} = args) do
|
||||
i2c = Comm.open(bus_name)
|
||||
|
||||
config =
|
||||
args
|
||||
|> Map.take([:gain, :int_time, :shutdown, :interrupt])
|
||||
|> Config.new()
|
||||
|
||||
Comm.write_config(config, i2c, address)
|
||||
:timer.send_interval(1_000, :measure)
|
||||
|
||||
state = %{
|
||||
i2c: i2c,
|
||||
address: address,
|
||||
config: config,
|
||||
last_reading: :no_reading
|
||||
}
|
||||
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
def init(args) do
|
||||
{bus_name, address} = Comm.discover()
|
||||
transport = "bus: #{bus_name}, address: #{address}"
|
||||
|
||||
Logger.info("Starting VEML6075. Please specify an address and a bus.")
|
||||
Logger.info("Starting on " <> transport)
|
||||
|
||||
defaults =
|
||||
args
|
||||
|> Map.put(:address, address)
|
||||
|> Map.put(:i2c_bus_name, bus_name)
|
||||
|
||||
init(defaults)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(
|
||||
:measure,
|
||||
%{i2c: i2c, address: address, config: config} = state
|
||||
) do
|
||||
last_reading_uva = Comm.readuva(i2c, address, config)
|
||||
last_reading_uvb = Comm.readuvb(i2c, address, config)
|
||||
|
||||
updated_with_reading = %{
|
||||
state
|
||||
| last_reading_uva: last_reading_uva,
|
||||
last_reading_uvb: last_reading_uvb
|
||||
}
|
||||
|
||||
{:noreply, updated_with_reading}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call(:get_measurement, _from, state) do
|
||||
{:reply, state.last_reading, state}
|
||||
end
|
||||
end
|
|
@ -0,0 +1,32 @@
|
|||
defmodule VEML6075.Comm do
|
||||
alias Circuits.I2C
|
||||
alias VEML6075.Config
|
||||
|
||||
@light_register_uva <<7>>
|
||||
@light_register_uvb <<9>>
|
||||
@visible_compensation <<a>>
|
||||
@ir_compensation <<b>>
|
||||
|
||||
def discover(possible_addresses \\ [0x10, 0x48]) do
|
||||
I2C.discover_one!(possible_addresses)
|
||||
end
|
||||
|
||||
def open(bus_name) do
|
||||
{:ok, i2c} = I2C.open(bus_name)
|
||||
i2c
|
||||
end
|
||||
|
||||
def write_config(configuration, i2c, sensor) do
|
||||
command = Config.to_integer(configuration)
|
||||
I2C.write(i2c, sensor, <<0, command::little-16>>)
|
||||
end
|
||||
|
||||
def read(i2c, sensor, configuration) do
|
||||
<<uva_raw::little-16>> = I2C.write_read!(i2c, sensor, @uva_register, 2)
|
||||
<<uvb_raw::little-16>> = I2C.write_read!(i2c, sensor, @uvb_register, 2)
|
||||
<<visible_compensation::little-16>> = I2C.write_read!(i2c, sensor, @uvb_register, 2)
|
||||
<<ir_compensation::little-16>> = I2C.write_read!(i2c, sensor, @uvb_register, 2)
|
||||
|
||||
Config.convert(configuration, uva_raw, uvb_raw, visible_compensation, ir_compensation)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,76 @@
|
|||
defmodule VEML6075.Config do
|
||||
defstruct uv_it: :it_100_ms,
|
||||
dynamic: false,
|
||||
uv_trig: false,
|
||||
uv_av: false,
|
||||
shutdown: false
|
||||
|
||||
def new, do: struct(__MODULE__)
|
||||
def new(opts), do: struct(__MODULE__, opts)
|
||||
|
||||
def to_integer(config) do
|
||||
reserved = 0
|
||||
|
||||
<<integer::16>> = <<
|
||||
reserved::9,
|
||||
uv_it(config.uv_it):3,
|
||||
high_dynamic(config.dynamic):1,
|
||||
uv_trig(config,uv_trig):1,
|
||||
uv_av(config.uv_av):1,
|
||||
shutdown(config.shutdown)::1
|
||||
>>
|
||||
|
||||
integer
|
||||
end
|
||||
|
||||
defp uv_it(:it_50_ms), do: 0b000
|
||||
defp uv_it(:it_100_ms), do: 0b001
|
||||
defp uv_it(:it_200_ms), do: 0b010
|
||||
defp uv_it(:it_400_ms), do: 0b011
|
||||
defp uv_it(:it_800_ms), do: 0b100
|
||||
|
||||
# Low dynamic: false, High dynamic: true
|
||||
defp high_dynamic(true), do: 1
|
||||
defp high_dynamic(_), do: 0
|
||||
|
||||
# No active force mode trigger: false, Trigger one measurement: true
|
||||
# With true, the sensor conducts one measurement every time, the host writes uv_trig = true, returns to 0 automatically
|
||||
defp uv_trig(true), do: 1
|
||||
defp uv_trig(_), do: 0
|
||||
|
||||
# Activive force mode disable (normal): false, active force mode enable: true
|
||||
defp uv_av(true), do: 1
|
||||
defp uv_av(_), do: 0
|
||||
|
||||
defp shutdown(true), do: 1
|
||||
defp shutdown(_), do: 0
|
||||
|
||||
calibration_alpha_vis = 1.0;
|
||||
calibration_beta_vis = 1.0;
|
||||
calibration_gamma_ir = 1.0;
|
||||
calibration_delta_ir = 1.0;
|
||||
|
||||
uva_vis_coef_a = 2.22
|
||||
uva_ir_coef_b = 1.33
|
||||
uvb_vis_coef_c = 2.95
|
||||
uvb_ir_coef_d = 1.75
|
||||
uva_responsibility = 0.00110
|
||||
uvb_responsibility = 0.00125
|
||||
|
||||
def convert(uva_raw, uvb_raw, visible_comp, ir_comp) do
|
||||
# Calculate the simple UVIA and UVIB. These are used to calculate the UVI signal.
|
||||
uvia = uva_raw - ((uva_vis_coef_a * calibration_alpha_vis * visible_comp) / calibration_gamma_ir)
|
||||
- ((uva_ir_coef_b * calibration_alpha_vis * ir_comp) / calibration_delta_ir)
|
||||
uvib = uvb_raw - ((uvb_vis_coef_c * calibration_beta_vis * visible_comp) / calibration_gamma_ir)
|
||||
- ((uvb_ir_coef_d * calibration_beta_vis * ir_comp) / calibration_delta_ir)
|
||||
|
||||
# Convert raw UVIA and UVIB to values scaled by the sensor responsivity
|
||||
uvia_scaled = uvia * (1.0 / calibration_alpha_vis) * uva_responsibility
|
||||
uvib_scaled = uvib * (1.0 / calibration_beta_vis) * uvb_responsibility
|
||||
|
||||
# Use UVIA and UVIB to calculate the average UVI:
|
||||
uvi = (uvia_scaled + uvib_scaled) / 2.0;
|
||||
|
||||
{uvia, uvib, uvi}
|
||||
end
|
||||
end
|
|
@ -0,0 +1,27 @@
|
|||
defmodule Veml6075.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :veml6075,
|
||||
version: "0.1.0",
|
||||
elixir: "~> 1.13",
|
||||
start_permanent: Mix.env() == :prod,
|
||||
deps: deps()
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help compile.app" to learn about applications.
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger]
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help deps" to learn about dependencies.
|
||||
defp deps do
|
||||
[
|
||||
{:circuits_i2c, "~> 1.0.1"}
|
||||
]
|
||||
end
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
%{
|
||||
"circuits_i2c": {:hex, :circuits_i2c, "1.0.1", "3a820dfa04bc5a92d0ec3c572cacb1a665802b2913fbc25784ed5a2020f12626", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "e11393b3f462154ebec5d100859bd5d616e958d9f701e4d62af5764ee84f5213"},
|
||||
"elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"},
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
ExUnit.start()
|
|
@ -0,0 +1,8 @@
|
|||
defmodule Veml6075Test do
|
||||
use ExUnit.Case
|
||||
doctest Veml6075
|
||||
|
||||
test "greets the world" do
|
||||
assert Veml6075.hello() == :world
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue