Skip to content

Commit

Permalink
Merge pull request #4 from SpaceTeam/class_refactorings
Browse files Browse the repository at this point in the history
Class refactorings
  • Loading branch information
r0f1 authored Dec 11, 2024
2 parents 690b5e9 + 76c207b commit a6f1d60
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 148 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/doc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: documentation

on: push

permissions:
contents: write

jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v4

- name: "Set up Python"
uses: actions/setup-python@v5
with:
python-version-file: ".python-version"

- name: Install the project
run: uv sync --all-extras --dev

- name: Build HTML
run: uv run sphinx-build docs/source docs/build/html

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: html-docs
path: docs/build/html

- name: Deploy
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/build/html
29 changes: 23 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[Github](https://github.com/SpaceTeam/STS1_sensor_libraries) | [PyPI](https://pypi.org/project/sts1-sensor-libraries/)
[Docs](https://spaceteam.github.io/STS1_sensor_libraries/) | [Github](https://github.com/SpaceTeam/STS1_sensor_libraries) | [PyPI](https://pypi.org/project/sts1-sensor-libraries/)

# sts1-sensor-libraries

Expand All @@ -12,8 +12,24 @@ The following sensors are available on the EDU module:
* [`L3GD20H`](https://www.pololu.com/file/0J731/L3GD20H.pdf) - Three-axis gyroscope.
* [`TMP112`](https://www.ti.com/product/TMP112) - High-accuracy temperature sensor.

## Quickstart

## Initial Setup on the Raspberry Pi
```python
from sts1_sensor_libraries import ADXL345, TMP112

# Accelerometer
accel = ADXL345(address=0x53, range=2, datarate=50)
x, y, z = accel.get_g()
print(f"X: {x:.2f}g, Y: {y:.2f}g, Z: {z:.2f}g")

# Temperature sensor
temp = TMP112(address=0x48)
print(f"{temp.get_temp():.2f} °C")
```

## Installation

### Initial Setup on the Raspberry Pi

* Open a terminal on the Raspberry Pi (e.g. via SSH).
* [Activate the I2C interface](https://www.raspberrypi-spy.co.uk/2014/11/enabling-the-i2c-interface-on-the-raspberry-pi/): `sudo raspi-config`
Expand All @@ -35,19 +51,20 @@ flo@raspberrypi:~ $ sudo i2cdetect -y 1
70: -- -- -- -- -- -- 76 --
```

## Installing the Python Package on the Raspberry Pi
### Installing the Python Package on the Raspberry Pi

If you want the latest stable version, install it like so:
```bash
pip install sts1-sensor-libraries
```

## Installation for Package Developers
## For Developers

* Install [just](https://github.com/casey/just?tab=readme-ov-file#pre-built-binaries)
* Install [just](https://github.com/casey/just?tab=readme-ov-file#pre-built-binaries): `curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to ~/bin`
* Install the [package manager uv](https://docs.astral.sh/uv/getting-started/installation/): `curl -LsSf https://astral.sh/uv/install.sh | sh`
* Add its path to your `~/.bashrc` such that the command `uv` is available: `export PATH=$HOME/.local/bin:$PATH`
* Clone this repo: `git clone https://github.com/SpaceTeam/STS1_sensor_libraries`
* Switch into the directory.
* Run `uv sync`. This creates a `.venv` folder and installs all necessary dependencies.
* Run one of the examples: `uv run python examples/ADXL345_example.py`
* Run `pytest`
* Run one of the examples: `uv run python examples/ADXL345_example.py`
9 changes: 8 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

import os
import sys
sys.path.insert(0, os.path.abspath('../../src'))

project = 'sts1-sensor-libraries'
copyright = '2024, Simon Köfinger, Florian Rohrer'
author = 'Simon Köfinger, Florian Rohrer'
Expand All @@ -14,7 +18,10 @@
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = ['myst_parser']
extensions = [
'sphinx.ext.githubpages',
'myst_parser'
]

templates_path = ['_templates']
exclude_patterns = []
Expand Down
2 changes: 1 addition & 1 deletion examples/ADXL345_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

log = structlog.get_logger()

accel = ADXL345(address=0x53, range=2, datarate=3200,
accel = ADXL345(address=0x53, range=2, datarate=50,
x_offset=-0.04570, y_offset=-0.00697, z_offset=0.04614)

while True:
Expand Down
13 changes: 0 additions & 13 deletions examples/TMP112Example.py

This file was deleted.

10 changes: 10 additions & 0 deletions examples/TMP112_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import time
import structlog
from sts1_sensor_libraries import TMP112

log = structlog.get_logger()
tmp = TMP112(address=0x48, conversion_rate=1)

while True:
log.info(f"{tmp.get_temp():.2f} °C")
time.sleep(.5)
4 changes: 2 additions & 2 deletions examples/calibration_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import time
from sts1_sensor_libraries import ADXL345

accel = ADXL345(address=0x53, range=2, datarate=3200)
accel = ADXL345(address=0x53, range=2, datarate=50)

measurements = []
for _ in range(500):
for _ in range(200):
measurements.append(accel.get_g())
time.sleep(.1)

Expand Down
20 changes: 4 additions & 16 deletions src/sts1_sensor_libraries/ADXL345.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
import os
from sts1_sensor_libraries.AbstractSensor import AbstractSensor

from smbus2 import SMBus

class ADXL345:
class ADXL345(AbstractSensor):
"""Digital accelerometer.
"""

possible_addresses = [0x1D, 0x3A, 0x3B, 0x53]
possible_datarates = [0.10, 0.20, 0.39, 0.78, 1.56, 3.13, 6.25, 12.5, 25, 50, 100, 200, 400, 800, 1600, 3200]
possible_ranges = [2, 4, 8, 16]

def __init__(self, bus=None, address=0x53, range=2, datarate=3200, x_offset=0, y_offset=0, z_offset=0):
if bus is None:
self.manage_bus = True
self.bus = SMBus(int(os.environ.get("STS1_SENSORS_I2C_ADDRESS", 1)))
else:
self.manage_bus = False
self.bus = bus
def __init__(self, bus=None, address=0x53, range=2, datarate=50, x_offset=0, y_offset=0, z_offset=0):
super().__init__(bus)

self.address = address
self.datarate = datarate
Expand All @@ -28,10 +20,6 @@ def __init__(self, bus=None, address=0x53, range=2, datarate=3200, x_offset=0, y
self.bus.write_byte_data(self.address, 0x2D, 0b1000)
self.bus.write_byte_data(self.address, 0x31, 0b1011 & self.possible_ranges.index(self.range))

def __del__(self):
if self.manage_bus:
self.bus.close()

@property
def address(self):
return self._address
Expand Down
16 changes: 16 additions & 0 deletions src/sts1_sensor_libraries/AbstractSensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import os

from smbus2 import SMBus

class AbstractSensor:
def __init__(self, bus=None):
if bus is None:
self.manage_bus = True
self.bus = SMBus(int(os.environ.get("STS1_SENSORS_I2C_BUS_ADDRESS", 1)))
else:
self.manage_bus = False
self.bus = bus

def __del__(self):
if self.manage_bus:
self.bus.close()
168 changes: 62 additions & 106 deletions src/sts1_sensor_libraries/TMP112.py
Original file line number Diff line number Diff line change
@@ -1,109 +1,65 @@
from smbus2 import i2c_msg
import logging

class TMP112:
poss_addr = [0x48, 0x49, 0x4A, 0x4B]
poss_conversionrate = [0.25, 1, 4, 8]
poss_conversionrate_bin = [0b00, 0b01, 0b10, 0b11]

config_set = 0
addr = 0
mode = 0b1 #1 ... extended mode (13-Bit -55°C - 150°C) 0 ... normal mode (12-Bit -55°C - 128°C)
conversionrate = 0

setConversionrate = False
setAddr = False
setupD = False
Error = False
consoleLog = True
from sts1_sensor_libraries.AbstractSensor import AbstractSensor

class TMP112(AbstractSensor):
"""Temperature sensor.
"""
possible_addresses = [0x48, 0x49, 0x4A, 0x4B]
possible_conversion_rates = [0.25, 1, 4, 8]

def __init__(self, bus):
self.addr = 0x48
self.bus = bus
def deact_consoleLog(self):
self.consoleLog = False
def set_mode(self, mode):
if mode == 1:
self.mode = 0b1
elif mode == 0:
self.mode = 0b0
elif self.consoleLog:
logging.error("TMP112: The mode entered is invalid. Please use 0 or 1 as the mode")
def set_address(self, address):
try:
self.poss_addr.index(address)
self.addr = address
self.setAddr = True
except ValueError:
s = "TMP112: The address (" + str(hex(address)) + ") you entered for the sensor TMP112 does not exist!"
if self.consoleLog:
logging.error(s)
s = "TMP112: Try one of the following:"
for value in self.poss_addr:
s = s + str(hex(value)) + " "
if self.consoleLog:
logging.info(s)
logging.error("TMP112: not initialized!!!")
def set_conversionrate(self, rate):
try:
self.poss_conversionrate.index(rate)
self.conversionrate = rate
self.setConversionrate = True
except ValueError:
s = "TMP112: The conversionrate (" + str(rate) + ") you entered for the sensor TMP112 does not exist!"
if self.consoleLog:
logging.error(s)
s = "TMP112: Try one of the following:"
for value in self.poss_conversionrate:
s = s + str(value) + " "
if self.consoleLog:
logging.info(s)
logging.error("TMP112: conversionrate not set!!!")
def setup(self):
if self.setAddr and self.setConversionrate:
#all settings correct
try:
msg = i2c_msg.write(self.addr, [0b00000001,0b01100000,0b00100000 + ((self.poss_conversionrate_bin[self.poss_conversionrate.index(self.conversionrate)]) << 6) + (self.mode << 4)])
self.bus.i2c_rdwr(msg)
except OSError as e:
self.Error = True
if e.errno == 121:
logging.error("ADXL345: Remote I/O Error: The device is not responding on the bus. Therefore it will be ignored")
else:
logging.error(f,"ADXL345: An error occurred: {e}")
return None

self.setupD = True
if self.consoleLog:
logging.info("TMP112: Setup finished, sensor ready.")
else:
if self.consoleLog:
logging.error("TMP112: Setup failed! Settings incorrect")
def getTemp(self):
if self.setupD:
msg_w = i2c_msg.write(self.addr, [0b00000000])
msg_r = i2c_msg.read(self.addr, 2)
self.bus.i2c_rdwr(msg_w)
self.bus.i2c_rdwr(msg_r)

byte = []
for value in msg_r:
byte.append(value)

raw = ((byte[0] << 8) + byte[1])>>(4-(self.mode))
#print(bin(raw))
#print(bin(raw>>(11+self.mode)))
if (raw>>(11+self.mode)) == 0b1:
#negative temp
raw = raw - (1<<(12+self.mode))
#raw = (1<<(12-self.mode)) - raw
#print("negativ")
temp = raw * 0.0625

return temp
else:
if self.consoleLog:
if self.Error:
logging.error("TMP112: not available")
else:
logging.error("TMP112: Setup not finished")
def __init__(self, bus=None, address=0x48, conversion_rate=1, extended_temp_range=True):
"""_summary_
:param bool extended_temp_range: If true, range: -55°C - 150°C, if false range: -55°C - 128°C, defaults to True
"""
super().__init__(bus)

self.address = address
self.conversion_rate = conversion_rate
self.extended_temp_range = extended_temp_range

c = self.possible_conversion_rates.index(self.conversion_rate)
m = int(self.extended_temp_range)
self.bus.i2c_rdwr(i2c_msg.write(self.address, [0b1,0b1100000,0b100000 + (c << 6) + (m << 4)]))

@property
def address(self):
return self._address

@address.setter
def address(self, address):
if address not in self.possible_addresses:
s = f"The address {hex(address)} does not exist."
s += f" Choose one of {self.possible_addresses}."
raise ValueError(s)
self._address = address

@property
def conversion_rate(self):
return self._conversion_rate

@conversion_rate.setter
def conversion_rate(self, conversion_rate):
if conversion_rate not in self.possible_conversion_rates:
s = f"The conversion_rate {conversion_rate} does not exist."
s += f" Choose one of {self.possible_conversion_rates}."
raise ValueError(s)
self._conversion_rate = conversion_rate

def get_temp(self):
msg_w = i2c_msg.write(self.address, [0])
msg_r = i2c_msg.read(self.address, 2)
self.bus.i2c_rdwr(msg_w)
self.bus.i2c_rdwr(msg_r)

byte = []
for value in msg_r:
byte.append(value)

m = int(self.extended_temp_range)

raw = ((byte[0] << 8) + byte[1]) >> (4-m)
if (raw >> (11 + m)) == 1:
raw = raw - (1 << (12 + m))
temp = raw * 0.0625
return temp
Loading

0 comments on commit a6f1d60

Please sign in to comment.