Home Posts Post Search Tag Search

Weather App 03 - New Firmware and Gather Data
Published on: 2025-08-04 Tags: elixir, Blog, Side Project, Nerves, Weather App

Capturing Sensor Data

    Okay so now that we are ready to move onto the capture part of the process we need to download the spec sheet for the environmental hat (https://www.waveshare.com/environment-sensor-hat.htm). Here are some of the information that we will need:
        Light Sensor
            I2C address: 0x29
        Temp/Humidity/Air Pressure
            I2c address: 0x76
        Motion Sensor: 
            I2C adress: 0x68
        UV Sensor:
            I2C address: 0x53
        VOC Sensor:
            I2C address: 0x59

    These might be different for your device I was able to look up the sensor data on line and it even has them on the board itself. Some of the sensors will have different sensitivities so be sure to check those out too.

    Now let's change a few deps and then upload the new firmware. 
        $ mix deps.get
        ...
        $ mix firmware
        ...
        $ mix upload
        ...
        $ ssh nerves.local
        ...

    So again my current settings I was unable to use the nerves.local so I had to create an firmware update script and then use that to upload it to the pi.
        mix firmware.gen.script # This is instead of the mix upload
        ./upload.sh 192.168.x.x $ Your IP address of the pi

    Now you can ssh into the device.
        ssh 192.168.x.x
                This is the way to do it with the basic sensor that the book is using.
                Here is where we will start to take some the sensor data.
                    ex(1)> alias Circuits.I2C
                    Circuits.I2C
                    iex(2)> sensor = 0x29 # This is the address of the light sensor
                    72
                    iex(3)> command = <<0>>
                    <<0>>
                    iex(4)> byte_size = 2
                    2
                    iex(5)> {:ok, i2c_ref} = I2C.open("i2c-1")
                    {:ok, #Reference<0.1635386997.268828675.62058>}
                    iex(6)> <<value::little-16>> = I2C.write_read!(i2c_ref, sensor, command, 2)
                    <<1, 0>>
                    iex(7)> value |> inspect(base: :binary)
                    "0b0"

                With the value of 0b0 being returned we know that the sensor is turned off. Let's turn it on.
                    iex(8)> config = 0b0001100000000000
                    6144
                    iex(9)> Circuits.I2C.write(i2c_ref, sensor, <<0, config::little-16>>)
                    :ok
                    iex(10)> <<value::little-16>> = I2C.write_read!(i2c_ref, sensor, command, 2)
                    <<0, 24>>
                    iex(11)> value |> inspect(base: :binary)
                    "0b1100000000000"

    This didn't work for me so Ill try an other way
        alias Circuits.I2C
        import Bitwise

        sensor = 0x29               # Sensor I2C address
        command_bit = 0x80          # Command bit to indicate command register (depends on sensor)
        enable_register = 0x00      # Register address to enable power and ALS
        config_register = 0x01      # Configuration register
        data_register = 0x14        # Data register address (where readings start)

        # Bit flags to enable power and ALS (ambient light sensing)
        enable_power_on = 0x01
        enable_als_enable = 0x02

        # Combine flags with bitwise OR
        enable_value = enable_power_on ||| enable_als_enable

        # Open I2C bus
        {:ok, i2c_ref} = I2C.open("i2c-1")

        # Write to enable register with command bit set
        I2C.write(i2c_ref, sensor, <<command_bit ||| enable_register, enable_value>>)

        # Optionally configure other registers here...

        # Read 2 bytes from the data register
        <<raw_value::little-16>> = I2C.write_read!(i2c_ref, sensor, <<command_bit ||| data_register>>, 2)

        IO.inspect(raw_value, base: :binary)

    Now we can start to do something with the sensor.
        iex(12)> light_reading = 4
        4
        iex(13)> <<value::little-16>> =
        ...(13)> Circuits.I2C.write_read!(i2c_ref, sensor, <<light_reading>>, 2)
        iex(14)> value
        440

    We get a value back. Now, put your hand over the sensor so that there’s less light and see if the value is lower:
        iex(15)> <<value::little-16>> =
        ...(15)> Circuits.I2C.write_read!(i2c_ref, sensor, <<light_reading>>, 2)
        iex(16)> value
        40

    Now we can try and transfor the data into something useful.
        iex(17)> measure_light = fn i2c, address ->
        ...(17)> <<value::little-16>> = I2C.write_read!(i2c, address, <<4>>, 2)
        ...(17)> value * 0.2304
        ...(17)> end
        #Function<43.97283095/2 in :erl_eval.expr/5>

        iex(16)> measure_light.(i2c_ref, sensor)
        57.6