Skip to content

Commit

Permalink
Merge pull request #2 from Keegan-Evans/docs
Browse files Browse the repository at this point in the history
DOCS: adding docs
  • Loading branch information
Keegan-Evans authored Dec 22, 2023
2 parents 0e52e16 + 19e0e90 commit db744a5
Show file tree
Hide file tree
Showing 18 changed files with 1,082 additions and 45 deletions.
1 change: 1 addition & 0 deletions .frontmatter/database/taxonomyDb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
62 changes: 62 additions & 0 deletions DOCS/Getting the firmware onto the Pico.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Getting the firmware onto the Pico.

## Preparing the Pico
You should ensure the pico's flash memory has been completely cleared of other code by

- Boot Pico in Developement Mode. To do so hold the `bootsel` button while
plugging the pico in.

- Drag the `flashnuke.uf2` firmware file onto the `RPI-RP2` drive to ensure the
Pico's memory has been completely cleared.[Flash Nuke
Download](https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html#resetting-flash-memory).

> **ⓘ** When developing for the pico, be sure to commment out the Watchdog
Timer in the `Sensor` class, as it will cause the Pico to reboot and disconnect
anytime an error is encountered, without emiting error information to your
developement environment, leading to a very frustrating experience. This can
happen in sneaky ways as well, such as if you previously had added a file that
was run on boot by the pico that contained code that ran the WDT, hence the
admonition to use the `flashnuke` firmware any time you are changing software on
the pico.

- When the `RPI-RP2` drive re-appears, drag the [latest MicroPython
firmware](https://micropython.org/download/RPI_PICO_W/) onto it. Be sure to get
the firmware for the Pico-W rather than Pico, as the `network` module is needed.

## Uploading Files


### Files to upload

- `main.py`: This is the file that is loaded by the Pico on boot. It should
contain a call to whatever run command your program requires. For examples look
in the `examples/mains` directory. If you would like to use one of these, simply
copy it to the Pico and rename to `main.py` so that MicroPython loads it on
boot.

- `sensor.py`: This file contains the base class definition to initialize the
Pico for use with the `Sensor-Hub` ecosystem.

- **I2C driver files**: Files that provide definitions to take measurements from
I2C sensors, must provide a measurement method that can be handed to the
`Sensor` class instance as a no-arguement function.

- `util.py`: Provides functionality such as automated network connectivity.

## After upload

Once the files are uploaded to the Pico, it should be ready to run. Upon first
boot and connection, the Pico should automatically download and install the
required `mqtt` micropython library. This may cause an error that seems to cause
the Pico to hang when it is finished installing, but should function normally
upon power cycling. Then as long as `Sensor-Hub` is within Wi-Fi range, it
should now connect and begin loggin data automatically.


## Other Tools

- [rshell](https://github.com/dhylands/rshell)

-
[MicroPico](https://marketplace.visualstudio.com/items?itemName=paulober.pico-w-go)(VSCode
Extension)
37 changes: 13 additions & 24 deletions DOCS/register_new_analog_sensor.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,31 @@
# Register New Analog Sensor
## Register New Analog Sensor

Analog sensors can be registered by passing a dictionary and base sensor instance to the `registre_analog_function_to_sensor` function found in the `registration` module.

Because the analog sensors rely on directly taking a reading from the end-point
Because analog sensors rely on directly taking a reading from the end-point
sensor, the only things we need to tell our board about them is what we would
like them to be called and the pin from which the analog reading should be
taken. The reading is taken using the Micropython `machine.ADC.read_u16`
function.

In addition to specifying the pin to be read and correctly attaching it, you should hook the power supply of the sensor to the `ADC_VREF` pin on the Pico(that is, pin #35).
In addition to specifying the pin to be read and correctly attaching it, you should hook the power supply of the sensor to the `ADC_VREF` pin on the Pico(that is, pin #35), from which the Pico supplies a stable reference voltage, against which the analog sensor reading can be taken.

### Registering the Soil Moisture Sensor

As an example, we will here register a capacitive soil moisture sensor to a Pico.

As an example, we will here register a capacitive soil moisture sensor to our pico.

To begin with, we create the dictionary that associates the name `soil_moisture_reg_test` to the pin number we want to take our reading from.

On the Pico, the pins available for use as ADC pins are 26, 27, and 28. It is possible to use other pins as ADC pins through careful software sampling, but that is well beyond the usecase here, but the option is available to developers in the future.
On the Pico, the pins available for use as analog-to-digital converter (ADC) pins are 26, 27, and 28. It is possible to use other pins as ADC pins through careful software sampling, but that is well beyond the usecase here, but the option is available to developers in the future.

Taking a look at the `soil_moisture.py` file in our library, the dictionary we use to define the soil moisture sensor looks like:
We can look at the `soil_moisture_main.py` file in the `mains` directory for how we can go about registering the soil moisture sensor.

```
sm = {'soil_moisture_reg_test': 28}
```
In turn this is imported during the demon, and then handed to our registration function(you can run this from `demos/demo_analog_sensor_registration.py`).

```
```python
from sensor import Sensor
from registration import register_analog_function_to_sensor
from soil_moisture import sm

sensor = Sensor(sensor_name="demo_sensor_1")
register_analog_function_to_sensor(sensor=sensor, def_dict=sm)
```
if __name__ == "__main__":
sensor = Sensor(sensor_name="soil_moisture_demo_1")
sensor.register_analog_sensor_function("soil_moisture", 28)

You must first initialize a base sensor instance, then hand that instance in as the `sensor` parameter of the registration function, and the dictionary associating the name with the pin number as the argument to `def_dict`.
sensor.run()
```

Whatever name use for the sensor will be recorded as the `measurement` name in the SensorHub database.
You must first initialize a base sensor instance, then use the `register_analog_sensor_function` method to name the reading to be taken from pin 28 "soil_moisture". Then at the specified reporting interval, the pico will take a reading from pin 28 and report it via MQTT message to the `Sensor-Hub`. Whatever name use for the sensor will be recorded as the `measurement` name in the `Sensor-Hub` database.

To check that the sensor was registered appropriately, you can print `<sensor-instance>.measurement_functions`, and you should see the name you provided as one of the keys in the output.
52 changes: 52 additions & 0 deletions DOCS/registering new I2C sensor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Registering A New I2C Sensor

The process of registering an I2C sensor are somewhat more challenging than
those of registering an analog sensor. That is because the interface for
interacting with each particular sensor is determined by the design of the
sensor itself. If there is not a pre-built library for the sensor available in
`Micropython`, then it will be necessary to write one from scratch. To do so, it
is often helpful to look at various Arduino libraries, such as [`Arduino
SensorKit`](https://github.com/arduino-libraries/Arduino_SensorKit), or the
sensor IC's data sheet. When implementing the driver library for the particular
sensor, the end goal is to create a single function call that will request and
return a reading from the sensor.

In the `Sensor` class, the method `register_i2c_sensor_function` takes the name
you would like the measurement to be given, and the actual function to be called
to get the reading from the sensor module. As of now, the only type of function
with a place to be registered are measurement functions, though it would be
possible to add registration for other types of I2C functions in the future.

## BME280 example
Here we will take a look at using the BME280 with the Pico. To see how this done
at a high level, we can take a look at `mains/atmospheric_main.py`:

```python
from sensor import Sensor
from bme280 import BME280

sensor = Sensor(sensor_name="atmospheric",
topic='sensor_data/atmospheric',
reporting_interval_sec=2,
I2CSensor=True)

environ_sensor = BME280(i2c=sensor.i2c_bus)
sensor.register_i2c_sensor_function('temperature',
environ_sensor.read_temperature)
sensor.register_i2c_sensor_function('humidity',
environ_sensor.read_humidity)
sensor.register_i2c_sensor_function('pressure',
environ_sensor.read_pressure)


sensor.run()
```

Here, the sensor functions are defined in the `bme280` module. There is a single
function to get the reading value of each of our target measurements,
`temperature`, `humidity`, and `pressure`.

Setting `I2CSensor` to `True` to tell the Sensor base class to initialize with a
I2C bus connection enabled. The bus connection here is passed to the `BME280`
class for use when it is calling I2C functions.

Loading

0 comments on commit db744a5

Please sign in to comment.