Skip to content

[FEATURE] Bring Back Big Data! #252

@Mikefly123

Description

@Mikefly123

Story

  • As a pysquared developer
  • I want an interface to all of the sensors on the satellite's solar panel faces
  • So that I can quickly and easily pull in data from them for downstream components.

Acceptance Criteria

  • Implement Protocol for Collecting Data from a Sensor Group
  • Create a Factory for Generating Groups of Sensors
  • Create a VEML7700 Ambient Light Sensor Manager Component
  • Create a MCP9808 Temperature Sensor Manager Component
  • Create a DRV2605L Haptic Motor Controller Manager Component

Technical Details

In v1.0.0 of the PROVES Kit software we had a class called Big_Data.py that, as the name implies, would generate a BIG amount of data by pulling in all of the sensor data from the satellite's exterior faces into a single (kinda gross) tuple that would then be passed along to other parts of the software for whatever it was needed for (beacon data, detumbling, you name it we would call Big_Data for it!).

This class was removed in the recent v2.0.0-alpha-25w17 release of the pysquared library and functionality will need to be reimplemented across multiple sub issues before the v2.0.0-beta release!

Legacy Big_Data Implementation for Reference

import gc

import adafruit_tca9548a as adafruit_tca9548a  # I2C Multiplexer

from .logger import Logger

try:
    from typing import Union

except Exception:
    pass


class Face:
    def __init__(
        self, add: int, pos: str, tca: adafruit_tca9548a.TCA9548A, logger: Logger
    ) -> None:
        self.tca: adafruit_tca9548a.TCA9548A = tca
        self.address: int = add
        self.position: str = pos
        self.logger: Logger = logger

        # Use tuple instead of list for immutable data
        self.senlist: tuple = ()
        # Define sensors based on position using a dictionary lookup instead of if-elif chain
        sensor_map: dict[str, tuple[str, ...]] = {
            "x+": ("MCP", "VEML", "DRV"),
            "x-": ("MCP", "VEML"),
            "y+": ("MCP", "VEML", "DRV"),
            "y-": ("MCP", "VEML"),
            "z-": ("MCP", "VEML", "DRV"),
        }
        self.senlist: tuple[str, ...] = sensor_map.get(pos, ())

        # Initialize sensor states dict only with needed sensors
        self.sensors: dict[str, bool] = {sensor: False for sensor in self.senlist}

        # Initialize sensor objects as None
        self.mcp = None
        self.veml = None
        self.drv = None

    def sensor_init(self, senlist, address) -> None:
        gc.collect()  # Force garbage collection before initializing sensors

        if "MCP" in senlist:
            try:
                import adafruit_mcp9808 as adafruit_mcp9808

                self.mcp: adafruit_mcp9808.MCP9808 = adafruit_mcp9808.MCP9808(
                    self.tca[address], address=27
                )
                self.sensors["MCP"] = True
            except Exception as e:
                self.logger.error("Error Initializing Temperature Sensor", e)

        if "VEML" in senlist:
            try:
                import adafruit_veml7700 as adafruit_veml7700

                self.veml: adafruit_veml7700.VEML7700 = adafruit_veml7700.VEML7700(
                    self.tca[address]
                )
                self.sensors["VEML"] = True
            except Exception as e:
                self.logger.error("Error Initializing Light Sensor", e)

        if "DRV" in senlist:
            try:
                import adafruit_drv2605 as adafruit_drv2605

                self.drv: adafruit_drv2605.DRV2605 = adafruit_drv2605.DRV2605(
                    self.tca[address]
                )
                self.sensors["DRV"] = True
            except Exception as e:
                self.logger.error("Error Initializing Motor Driver", e)

        gc.collect()  # Clean up after initialization


class AllFaces:
    def __init__(self, tca: adafruit_tca9548a.TCA9548A, logger: Logger) -> None:
        self.tca: adafruit_tca9548a.TCA9548A = tca
        self.faces: list[Face] = []
        self.logger: Logger = logger

        # Create faces using a loop instead of individual variables
        positions: list[tuple[str, int]] = [
            ("y+", 0),
            ("y-", 1),
            ("x+", 2),
            ("x-", 3),
            ("z-", 4),
        ]
        for pos, addr in positions:
            face: Face = Face(addr, pos, tca, self.logger)
            face.sensor_init(face.senlist, face.address)
            self.faces.append(face)
            gc.collect()  # Clean up after each face initialization

    def face_test_all(self) -> list[list[float]]:
        results: list[list[float]] = []
        for face in self.faces:
            if face:
                try:
                    temp: Union[float, None] = (
                        face.mcp.temperature if face.sensors.get("MCP") else None
                    )
                    light: Union[float, None] = (
                        face.veml.lux if face.sensors.get("VEML") else None
                    )
                    results.append([temp, light])
                except Exception:
                    results.append([None, None])
        return results

Sub-issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions