Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/pip/paho-mqtt-lt-3
Browse files Browse the repository at this point in the history
  • Loading branch information
bee-mois authored Apr 22, 2024
2 parents 0664e2d + d1a22d9 commit 5309e71
Show file tree
Hide file tree
Showing 14 changed files with 82 additions and 16 deletions.
10 changes: 10 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

## Unreleased

## v0.0.4 - 2024-04-21
- Grafana Dashboard: Trim identifying information: `id`, `uid`,
`version`. Thanks, @bee-mois.
- Emit user admonition on `make-config` subcommand. Thanks,
@bee-mois.
- Data Model: Make MQTT settings optional, to allow running the
data logger without configuring them.
- Allow defining per-sensor offsets within the configuration
file. Thanks, @bee-mois.

## v0.0.3 - 2024-04-20
- Tests: Make sensor tests work, using a fake sysfs filesystem
- Tests: Added basic test case for CLI interface
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ On our community forum, you can find relevant discussions about this topic.

## Acknowledgements

The original code this implementation has been derived from has been discovered
The original code of this implementation has been discovered
on the element14 community forum at [Multiple DS18B20 Temp sensors interfacing
with Raspberry Pi], shared by [@laluha]. Thanks!

Expand Down
4 changes: 3 additions & 1 deletion docs/backlog.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Backlog for ds18b20-datalogger

## Iteration +1
- Documentation: How to set up Kotori DAQ
- Documentation: MQTT publishing guide
- Documentation: How to provision Grafana Dashboard
- Documentation: How to set up Kotori DAQ
- Documentation: Better describe the 5x6 temperature sensor matrix

## Iteration +2
- By default, probe configuration at `/etc/ds18b20-datalogger/config.yaml`
Expand Down
1 change: 1 addition & 0 deletions docs/production.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ document.
## Installation
```shell
sudo su -
mkdir -p /etc/ds18b20-datalogger
python3 -m venv /opt/ds18b20-datalogger
/opt/ds18b20-datalogger/bin/pip install ds18b20-datalogger
/opt/ds18b20-datalogger/bin/ds18b20-datalogger make-config > /etc/ds18b20-datalogger/config.yaml
Expand Down
4 changes: 4 additions & 0 deletions ds18b20_datalogger/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from ds18b20_datalogger.core import read_ds18b20_sensor_matrix, send_measurement_mqtt
from ds18b20_datalogger.model import Settings
from ds18b20_datalogger.util import msg

if sys.version_info < (3, 9):
from importlib_resources import files # pragma: nocover
Expand Down Expand Up @@ -33,6 +34,9 @@ def main():
send_measurement_mqtt(settings.mqtt, reading)

elif subcommand == "make-config":
print( # noqa: T201
msg("Please make sure to edit the configuration file before starting the program."), file=sys.stderr
)
config_template = files("ds18b20_datalogger") / "datalogger.yaml"
print(config_template.read_text(), file=sys.stdout) # noqa: T201

Expand Down
2 changes: 2 additions & 0 deletions ds18b20_datalogger/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,7 @@ def read_ds18b20_sensor_matrix(devicemap: DeviceMap) -> Reading:
reading = Reading()
for device in devicemap.devices:
value = read_temp(device.path)
if value is not None and device.offset is not None:
value += device.offset
reading.add_measurement(name=device.name, value=value)
return reading
6 changes: 6 additions & 0 deletions ds18b20_datalogger/datalogger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@ mqtt:
one-wire:
- name: temp-ir-1-1
path: /sys/bus/w1/devices/28-0346d4430b06
offset: null
- name: temp-ir-1-2
path: /sys/bus/w1/devices/28-0cf3d443ba40
offset: null
- name: temp-ir-1-3
path: /sys/bus/w1/devices/28-0e49d44343bd
offset: null
- name: temp-ir-2-1
path: /sys/bus/w1/devices/28-2231d443d266
offset: null
- name: temp-ir-2-2
path: /sys/bus/w1/devices/28-282bd4430f5e
offset: null
- name: temp-ir-2-3
path: /sys/bus/w1/devices/28-2846d443e4f2
offset: null
16 changes: 9 additions & 7 deletions ds18b20_datalogger/grafana-dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": 924,
"links": [
{
"icon": "external link",
Expand Down Expand Up @@ -1994,9 +1993,14 @@
"schemaVersion": 22,
"style": "dark",
"tags": [
"instant",
"hiveeyes",
"mois"
"beehive monitoring",
"ds18b20",
"grafana",
"kotori daq",
"mqtt",
"raspberry pi",
"sensor network",
"temperature matrix"
],
"templating": {
"list": []
Expand Down Expand Up @@ -2035,9 +2039,7 @@
},
"timezone": "browser",
"title": "DS18B20 Temperature Matrix Heatmap 5x6",
"uid": "T49wHSaIk",
"variables": {
"list": []
},
"version": 7
}
}
10 changes: 7 additions & 3 deletions ds18b20_datalogger/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Device:

name: str
path: str
offset: t.Union[float, None] = None


class DeviceMap:
Expand Down Expand Up @@ -66,16 +67,19 @@ class Settings:
General settings container.
"""

mqtt: MqttSettings
devicemap: DeviceMap
mqtt: t.Union[MqttSettings, None]
devicemap: t.Union[DeviceMap, None]

@classmethod
def from_file(cls, configfile: Path):
data = yaml.safe_load(configfile.read_text())
devicemap = DeviceMap()
for item in data["one-wire"]:
devicemap.devices.append(Device(**item))
return cls(mqtt=MqttSettings(**data["mqtt"]), devicemap=devicemap)
mqtt = None
if "mqtt" in data:
mqtt = MqttSettings(**data["mqtt"])
return cls(mqtt=mqtt, devicemap=devicemap)


@dataclasses.dataclass
Expand Down
7 changes: 7 additions & 0 deletions ds18b20_datalogger/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ def partition(lst, chunksize: int) -> Generator[List[Any], None, None]:
"""
for i in range(0, len(lst), chunksize):
yield list(itertools.islice(lst, i, i + chunksize))


def msg(text: str):
"""
Return a text armoured with ANSI codes to make it appear in bright yellow.
"""
return f"\033[1;33m{text}\033[0m"
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ develop = [
"black<25",
"mypy<1.10",
"poethepoet<0.26",
"pyproject-fmt<1.8",
"ruff<0.4",
"pyproject-fmt<1.9",
"ruff<0.5",
"validate-pyproject<0.17",
]
docs = [
Expand Down
11 changes: 11 additions & 0 deletions tests/datalogger-offset.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Test configuration file for validating per-sensor offsets.

one-wire:
- name: temp-ir-1-1
path: /sys/bus/w1/devices/28-0346d4430b06
offset: -0.5
- name: temp-ir-1-2
path: /sys/bus/w1/devices/28-0cf3d443ba40
offset: null
- name: temp-ir-1-3
path: /sys/bus/w1/devices/28-0e49d44343bd
6 changes: 4 additions & 2 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@ def test_cli_run_almost_success():


def test_cli_make_config():
exitcode, output = invoke("ds18b20-datalogger make-config")
config = yaml.safe_load(output)
command = shlex.split("ds18b20-datalogger make-config")
process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # noqa: S603
config = yaml.safe_load(process.stdout)
assert "mqtt" in config
assert "one-wire" in config
assert b"Please make sure to edit the configuration" in process.stderr


def test_cli_make_dashboard():
Expand Down
15 changes: 15 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,18 @@ def test_sensors_none(settings):
def test_telemetry(settings):
reading = read_ds18b20_sensor_matrix(settings.devicemap)
send_measurement_mqtt(settings.mqtt, reading)


@pytest.fixture
def offset_settings() -> Settings:
configfile = Path("tests") / "datalogger-offset.yaml"
return Settings.from_file(configfile)


def test_sensors_offset(offset_settings, fake_hardware_success):
reading = read_ds18b20_sensor_matrix(offset_settings.devicemap)
assert reading.to_dict() == {
"temp-ir-1-1": -0.499,
"temp-ir-1-2": 0.002,
"temp-ir-1-3": 0.003,
}

0 comments on commit 5309e71

Please sign in to comment.