Skip to content

Commit

Permalink
Add support for BME688 sensor
Browse files Browse the repository at this point in the history
* Adds a new table to store BME688 data since the sensor is already onboard

* Includes the SVM41 and BME688 data in the summary template render
  • Loading branch information
Wason1797 committed Dec 13, 2024
1 parent 855a91d commit 30fcd77
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 10 deletions.
52 changes: 51 additions & 1 deletion server/app/managers/aiq_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@

from sqlalchemy import delete, func, select

from app.repositories.db.models import ENS160Data, SCD41Data, StationData, SVM41Data
from app.repositories.db.models import BME688Data, ENS160Data, SCD41Data, StationData, SVM41Data
from app.serializers.request import AiqDataFromStation
from app.types import AsyncSessionMaker

SUMMARY_TEMPLATE = """
Row Count: {}
{}
{}
{}
{}
border_router_id: {}
station_id: {}
"""
Expand All @@ -29,6 +31,22 @@
\ttvoc: {} ppb
"""

SVM41_SUMMARY_TEMPLATE = """
SVM41:
\ttemp: {} C
\thum: {} H%
\tnox: {}
\tvoc: {}
"""

BME688_SUMMARY_TEMPLATE = """
BME688:
\ttemp: {} C
\thum: {} H%
\tpress: {} KPa
\tgasres: {} Ohm
"""


def _render_summary_template(data: StationData, count: int) -> str:
scd41_summary = (
Expand All @@ -51,10 +69,34 @@ def _render_summary_template(data: StationData, count: int) -> str:
else ""
)

svm41_summary = (
SVM41_SUMMARY_TEMPLATE.format(
int(data.svm41_data.temperature) / 1000000,
int(data.svm41_data.humidity) / 1000000,
int(data.svm41_data.voc_index) / 1000000,
int(data.svm41_data.nox_index) / 1000000,
)
if data.svm41_data is not None
else ""
)

bme688_summary = (
BME688_SUMMARY_TEMPLATE.format(
int(data.bme688_data.temperature) / 1000000,
int(data.bme688_data.humidity) / 1000000,
int(data.bme688_data.pressure) / 1000000,
int(data.bme688_data.gas_resistance) / 1000000,
)
if data.bme688_data is not None
else ""
)

return SUMMARY_TEMPLATE.format(
count,
scd41_summary,
ens160_summary,
svm41_summary,
bme688_summary,
data.border_router_id,
data.station_id,
)
Expand Down Expand Up @@ -91,6 +133,14 @@ async def save_sensor_data(
voc_index=data.svm41_d.voc.to_str_number(),
)

if data.bme688_d:
sensor_data.bme688_data = BME688Data(
temperature=data.bme688_d.temp.to_str_number(),
humidity=data.bme688_d.hum.to_str_number(),
pressure=data.bme688_d.press.to_str_number(),
gas_resistance=data.bme688_d.gasres.to_str_number(),
)

async with session_maker() as session:
session.add(sensor_data)
await session.commit()
Expand Down
16 changes: 15 additions & 1 deletion server/app/repositories/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ class SVM41Data(BaseDBConnector.Base):
__table_args__ = (PrimaryKeyConstraint("id", name="pk_esvm41_data"),)


class BME688Data(BaseDBConnector.Base):
__tablename__ = "bme688_data"

id: Mapped[int] = mapped_column(INTEGER(), primary_key=True, autoincrement=True, nullable=False)
temperature: Mapped[str] = mapped_column(VARCHAR(20), nullable=False)
humidity: Mapped[str] = mapped_column(VARCHAR(20), nullable=False)
pressure: Mapped[str] = mapped_column(VARCHAR(20), nullable=False)
gas_resistance: Mapped[str] = mapped_column(VARCHAR(20), nullable=False)

__table_args__ = (PrimaryKeyConstraint("id", name="pk_bme688_data"),)


class StationData(BaseDBConnector.Base):
__tablename__ = "station_data"

Expand All @@ -46,6 +58,7 @@ class StationData(BaseDBConnector.Base):
scd41_data_id: Mapped[int] = mapped_column(INTEGER(), ForeignKey("scd41_data.id"), nullable=True)
ens160_data_id: Mapped[int] = mapped_column(INTEGER(), ForeignKey("ens160_data.id"), nullable=True)
svm41_data_id: Mapped[int] = mapped_column(INTEGER(), ForeignKey("svm41_data.id"), nullable=True)
bme688_data_id: Mapped[int] = mapped_column(INTEGER(), ForeignKey("bme688_data.id"), nullable=True)

# Id of the individual sensor station submitting the data
station_id: Mapped[int] = mapped_column(INTEGER(), ForeignKey("stations.id"), nullable=False)
Expand All @@ -56,7 +69,8 @@ class StationData(BaseDBConnector.Base):

scd41_data: Mapped[SCD41Data] = relationship("SCD41Data", lazy="joined")
ens160_data: Mapped[ENS160Data] = relationship("ENS160Data", lazy="joined")
svm41_data: Mapped[ENS160Data] = relationship("SVM41Data", lazy="joined")
svm41_data: Mapped[SVM41Data] = relationship("SVM41Data", lazy="joined")
bme688_data: Mapped[BME688Data] = relationship("BME688Data", lazy="joined")

__table_args__ = (PrimaryKeyConstraint("id", name="pk_station_data"),)

Expand Down
12 changes: 6 additions & 6 deletions server/app/serializers/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ class SVM41Data(BaseModel):
voc: SensorData


class SPS30Data(BaseModel):
pm1: SensorData
pm25: SensorData
pm10: SensorData
tsize: SensorData
class BME688Data(BaseModel):
hum: SensorData
temp: SensorData
press: SensorData
gasres: SensorData


class AiqDataFromStation(BaseModel):
scd41_d: Optional[SCD41Data] = None
svm41_d: Optional[SVM41Data] = None
ens160_d: Optional[ENS160Data] = None
sps30_d: Optional[SPS30Data] = None
bme688_d: Optional[BME688Data] = None
station_id: int
41 changes: 41 additions & 0 deletions server/migrations/versions/74b685228bd5_add_support_for_bme688.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""Add support for bme688
Revision ID: 74b685228bd5
Revises: 3953e2822334
Create Date: 2024-12-13 17:16:27.391847
"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = '74b685228bd5'
down_revision: Union[str, None] = '3953e2822334'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('bme688_data',
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('temperature', sa.VARCHAR(length=20), nullable=False),
sa.Column('humidity', sa.VARCHAR(length=20), nullable=False),
sa.Column('pressure', sa.VARCHAR(length=20), nullable=False),
sa.Column('gas_resistance', sa.VARCHAR(length=20), nullable=False),
sa.PrimaryKeyConstraint('id', name='pk_bme688_data')
)
op.add_column('station_data', sa.Column('bme688_data_id', sa.INTEGER(), nullable=True))
op.create_foreign_key(None, 'station_data', 'bme688_data', ['bme688_data_id'], ['id'])
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'station_data', type_='foreignkey')
op.drop_column('station_data', 'bme688_data_id')
op.drop_table('bme688_data')
# ### end Alembic commands ###
23 changes: 23 additions & 0 deletions server/tests/fixtures/sensor_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,26 @@ def scd41_data_from_station() -> AiqDataFromStation:
"station_id": 1,
}
)


@pytest.fixture
def full_data_from_station() -> AiqDataFromStation:
return AiqDataFromStation.model_validate(
{
"scd41_d": {"co2": {"val1": 542, "val2": 0}, "temp": {"val1": 24, "val2": 118791}, "hum": {"val1": 27, "val2": 774047}},
"ens160_d": {"eco2": 554, "tvoc": 103, "aqi": 2},
"bme688_d": {
"gasres": {"val1": 12946860, "val2": 0},
"press": {"val1": 101, "val2": 118000},
"temp": {"val1": 28, "val2": 680000},
"hum": {"val1": 18, "val2": 60000},
},
"svm41_d": {
"temp": {"val1": 28, "val2": 680000},
"hum": {"val1": 18, "val2": 60000},
"nox": {"val1": 500, "val2": 0},
"voc": {"val1": 400, "val2": 0},
},
"station_id": 1,
}
)
16 changes: 14 additions & 2 deletions server/tests/managers/aiq_manager_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@


@pytest.mark.asyncio
async def test_save_sensor_data(main_db_session: AsyncSessionMaker, scd41_data_from_station: AiqDataFromStation) -> None:
db_id = await AiqDataManager.save_sensor_data(main_db_session, scd41_data_from_station)
async def test_save_sensor_data(main_db_session: AsyncSessionMaker, full_data_from_station: AiqDataFromStation) -> None:
db_id = await AiqDataManager.save_sensor_data(main_db_session, full_data_from_station)

data_in_db = await AiqDataManager.get_sensor_data_by_id(main_db_session, db_id)

Expand All @@ -33,6 +33,18 @@ async def test_get_summary(main_db_session: AsyncSessionMaker, scd41_data_from_s
assert summary is not None


@pytest.mark.asyncio
async def test_get_summary_with_full_data(main_db_session: AsyncSessionMaker, full_data_from_station: AiqDataFromStation):
await AiqDataManager.save_sensor_data(main_db_session, full_data_from_station)
summary = await AiqDataManager.get_summary(main_db_session)

assert summary is not None
assert "SCD41" in summary
assert "SVM41" in summary
assert "ENS160" in summary
assert "BME688" in summary


@pytest.mark.asyncio
async def test_get_summary_by_station_id(main_db_session: AsyncSessionMaker, scd41_data_from_station: AiqDataFromStation):
await AiqDataManager.save_sensor_data(main_db_session, scd41_data_from_station)
Expand Down

0 comments on commit 30fcd77

Please sign in to comment.