Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DS2482S-800 support #6

Merged
merged 3 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Introduction


.. image:: https://readthedocs.org/projects/adafruit-circuitpython-ds248x/badge/?version=latest
:target: https://docs.circuitpython.org/projects/ds248x/en/latest/
:target: https://adafruit-circuitpython-ds248x.readthedocs.io/en/latest/
:alt: Documentation Status


Expand Down
96 changes: 73 additions & 23 deletions adafruit_ds248x.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
**Hardware:**

* `Adafruit DS2484 I2C to 1-Wire Bus Adapter Breakout <https://www.adafruit.com/product/5976>`_
* `Adafruit DS2482S-800 8 Channel I2C to 1-Wire Breakout <https://www.adafruit.com/product/6027>`_

**Software and Dependencies:**

Expand Down Expand Up @@ -46,6 +47,7 @@
_1WIRE_WRITE_BYTE = const(0xA5)
_1WIRE_READ_BYTE = const(0x96)
_TRIPLET = const(0x78)
_CHANNEL_SELECT = const(0xC3)

# DS248x Register Definitions
_REG_STATUS = const(0xF0)
Expand All @@ -61,7 +63,7 @@

class Adafruit_DS248x:
"""
Driver for the DS2484 1-Wire to I2C Bus Adapter.
Driver for the DS248x 1-Wire to I2C Bus Adapter.
"""

def __init__(self, i2c: I2C, address: int = 0x18):
Expand All @@ -74,6 +76,7 @@ def __init__(self, i2c: I2C, address: int = 0x18):
try:
self.i2c_device = I2CDevice(i2c, address)
self._address = address
self._selected_channel = -1
self.rom_no: bytearray = bytearray(8)
self.last_discrepancy: int = 0
self.last_device_flag: bool = False
Expand All @@ -87,7 +90,9 @@ def __init__(self, i2c: I2C, address: int = 0x18):
raise RuntimeError("\tNo presence pulse")
time.sleep(1)
except RuntimeError as exception:
raise RuntimeError("DS248x initialization failed.") from exception
raise RuntimeError(
f"DS248x initialization failed: {exception}"
) from exception

def reset(self) -> bool:
"""
Expand Down Expand Up @@ -374,37 +379,82 @@ def branch_dir_taken(self) -> bool:
status = self.status
return status != 0xFF and (status & 0x80)

def ds18b20_temperature(self, rom: bytearray) -> float:
def ds18b20_temperature(self, rom: bytearray = None) -> float:
"""
Reads the temperature from a DS18B20 sensor.
Reads the temperature from a DS18B20 sensor. If no ROM address is provided,
then a channel is read (0-7) from the DS2482S-800.

:param rom: The ROM address of the DS18B20 sensor
:param rom: The ROM address of the DS18B20 sensor (optional)
:return: The temperature in Celsius
"""
if rom[0] != _DS18B20_FAMILY:
raise ValueError("Device attached is not a DS18B20")

self.onewire_reset()
self.onewire_byte = 0x55 # Match ROM command
for byte in rom:
self.onewire_byte = byte

self.onewire_byte = 0x44 # Convert T command
if rom:
if rom[0] != _DS18B20_FAMILY:
raise ValueError("Device attached is not a DS18B20")
# Match ROM if a ROM address is provided
self.onewire_reset()
self.onewire_byte = 0x55
for byte in rom:
self.onewire_byte = byte
else:
# Skip ROM if no ROM address is provided
self.onewire_reset()
self.onewire_byte = 0xCC
self.onewire_byte = 0x44
time.sleep(0.75)

self.onewire_reset()
self.onewire_byte = 0x55
for byte in rom:
self.onewire_byte = byte
self.onewire_byte = 0xBE # Read Scratchpad command

if rom:
self.onewire_reset()
self.onewire_byte = 0x55
for byte in rom:
self.onewire_byte = byte
else:
self.onewire_reset()
self.onewire_byte = 0xCC
self.onewire_byte = 0xBE
data = bytearray(9)
for i in range(9):
data[i] = self.onewire_byte

raw = (data[1] << 8) | data[0]
if raw & 0x8000:
raw -= 1 << 16
celsius = raw / 16.0

return celsius

@property
def channel(self) -> int:
"""
Gets the current selected channel on the DS2482-800 by querying the device.

:return: The currenctly selected channel.
"""
if self._selected_channel is None:
raise ValueError("No channel has been selected yet")
channel_code = self._selected_channel + (~self._selected_channel << 4) & 0xFF
cmd = bytearray([_CHANNEL_SELECT, channel_code])
reply = bytearray(1)
with self.i2c_device as i2c:
i2c.write(cmd)
i2c.readinto(reply)
return_codes = [0xB8, 0xB1, 0xAA, 0xA3, 0x9C, 0x95, 0x8E, 0x87]
if reply[0] in return_codes:
return return_codes.index(reply[0])
raise ValueError("Unknown channel code returned from the device")

@channel.setter
def channel(self, chan: int) -> None:
"""
Sets the channel on the DS2482-800.

:param chan: Channel to use, from 0 to 7 inclusive
"""
if chan > 7:
raise ValueError("Channel must be between 0 and 7")
channel_code = chan + (~chan << 4) & 0xFF
cmd = bytearray([_CHANNEL_SELECT, channel_code])
reply = bytearray(1)
with self.i2c_device as i2c:
i2c.write(cmd)
i2c.readinto(reply)
return_codes = [0xB8, 0xB1, 0xAA, 0xA3, 0x9C, 0x95, 0x8E, 0x87]
if return_codes[chan] != reply[0]:
raise RuntimeError("Failed to set the channel")
self._selected_channel = chan
9 changes: 9 additions & 0 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,12 @@ Ensure your device works with this simple test.
.. literalinclude:: ../examples/ds248x_simpletest.py
:caption: examples/ds248x_simpletest.py
:linenos:

DS2482S-800 8-Channel example
-----------------------------

Read all 8 channels from the DS2482S-800

.. literalinclude:: ../examples/ds2482s-800_8-channel_test.py
:caption: examples/ds2482s-800_8-channel_test.py
:linenos:
22 changes: 22 additions & 0 deletions examples/ds2482s-800_8-channel_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# SPDX-FileCopyrightText: Copyright (c) 2024 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""Adafruit DS2482S-800 8-Channel DS18B20 Example"""

import time
import board
from adafruit_ds248x import Adafruit_DS248x

# Initialize I2C bus and DS248x
i2c = board.STEMMA_I2C()
ds248x = Adafruit_DS248x(i2c)

while True:
for i in range(8):
ds248x.channel = i
print(f"Reading channel {ds248x.channel}")
temperature = ds248x.ds18b20_temperature()
print(f"Temperature: {temperature:.2f} °C")
print()
time.sleep(1)