pamoja.sensors

Idiomatic sensor-driver facade.

These are the decode half of eleven parts a field node is likely to have wired to it, turning the register bytes a bus driver read into the physical reading the manufacturer's datasheet says they mean. The BME280 also has a driver, which runs the datasheet's whole conversation over an I2cBus from pamoja.hal, and a simulated part that answers it with nothing plugged in.

   1"""Idiomatic sensor-driver facade.
   2
   3These are the decode half of eleven parts a field node is likely to have wired to
   4it, turning the register bytes a bus driver read into the physical reading the
   5manufacturer's datasheet says they mean. The BME280 also has a driver, which runs
   6the datasheet's whole conversation over an `I2cBus` from :mod:`pamoja.hal`, and a
   7simulated part that answers it with nothing plugged in.
   8"""
   9
  10from __future__ import annotations
  11
  12import enum
  13from typing import List, Optional
  14
  15from pamoja.hal import CommandPart, I2cBus, I2cPart, WordPart
  16
  17from pamoja._native import Ads1115Config, Bme280Calibration, Bme280Measurement, Ds18b20Reading
  18from pamoja._native import Bme280 as _NativeBme280
  19from pamoja._native import Bme280Config, Bme280CtrlMeas
  20from pamoja._native import bme280_config_bits as _bme280_config_bits
  21from pamoja._native import bme280_config_from_bits as _bme280_config_from_bits
  22from pamoja._native import bme280_ctrl_hum_bits as _bme280_ctrl_hum_bits
  23from pamoja._native import bme280_ctrl_hum_from_bits as _bme280_ctrl_hum_from_bits
  24from pamoja._native import bme280_ctrl_meas_bits as _bme280_ctrl_meas_bits
  25from pamoja._native import bme280_ctrl_meas_from_bits as _bme280_ctrl_meas_from_bits
  26from pamoja._native import bme280_filter_coefficient as _bme280_filter_coefficient
  27from pamoja._native import bme280_image_updating as _bme280_image_updating
  28from pamoja._native import bme280_max_measurement_micros as _bme280_max_measurement_micros
  29from pamoja._native import bme280_measuring as _bme280_measuring
  30from pamoja._native import bme280_oversampling_factor as _bme280_oversampling_factor
  31from pamoja._native import bme280_sim_burst as _bme280_sim_burst
  32from pamoja._native import bme280_sim_burst_for as _bme280_sim_burst_for
  33from pamoja._native import bme280_sim_calibration as _bme280_sim_calibration
  34from pamoja._native import (
  35    bme280_sim_calibration_humidity as _bme280_sim_calibration_humidity,
  36)
  37from pamoja._native import bme280_sim_part as _bme280_sim_part
  38from pamoja._native import bme280_sim_reporting as _bme280_sim_reporting
  39from pamoja._native import bme280_standby_micros as _bme280_standby_micros
  40from pamoja._native import (
  41    bme280_typical_measurement_micros as _bme280_typical_measurement_micros,
  42)
  43from pamoja._native import ads1115_config_bits as _ads1115_config_bits
  44from pamoja._native import ads1115_config_from_bits as _ads1115_config_from_bits
  45from pamoja._native import ads1115_full_scale_microvolts as _ads1115_full_scale_microvolts
  46from pamoja._native import ads1115_samples_per_second as _ads1115_samples_per_second
  47from pamoja._native import ads1115_to_nanovolts as _ads1115_to_nanovolts
  48from pamoja._native import ads1115_to_volts as _ads1115_to_volts
  49from pamoja._native import ds18b20_build_scratchpad as _ds18b20_build_scratchpad
  50from pamoja._native import ds18b20_celsius as _ds18b20_celsius
  51from pamoja._native import ds18b20_config_byte as _ds18b20_config_byte
  52from pamoja._native import ds18b20_crc8 as _ds18b20_crc8
  53from pamoja._native import ds18b20_max_conversion_micros as _ds18b20_max_conversion_micros
  54from pamoja._native import ds18b20_micro_celsius as _ds18b20_micro_celsius
  55from pamoja._native import ds18b20_parse_scratchpad as _ds18b20_parse_scratchpad
  56from pamoja._native import ds18b20_resolution_bits as _ds18b20_resolution_bits
  57from pamoja._native import ds18b20_step_micro_celsius as _ds18b20_step_micro_celsius
  58from pamoja._native import ina219_bus_register as _ina219_bus_register
  59from pamoja._native import ina219_current_register as _ina219_current_register
  60from pamoja._native import ina219_power_register as _ina219_power_register
  61from pamoja._native import ina219_shunt_register as _ina219_shunt_register
  62from pamoja._native import ina219_bus_millivolts as _ina219_bus_millivolts
  63from pamoja._native import ina219_calibration as _ina219_calibration
  64from pamoja._native import ina219_conversion_ready as _ina219_conversion_ready
  65from pamoja._native import ina219_current_microamps as _ina219_current_microamps
  66from pamoja._native import ina219_math_overflow as _ina219_math_overflow
  67from pamoja._native import (
  68    ina219_minimum_current_lsb_microamps as _ina219_minimum_current_lsb_microamps,
  69)
  70from pamoja._native import ina219_power_microwatts as _ina219_power_microwatts
  71from pamoja._native import ina219_shunt_microvolts as _ina219_shunt_microvolts
  72from pamoja._native import (
  73    Bmp280Calibration,
  74    Bmp280Coefficients,
  75    Bmp280Config,
  76    Bmp280CtrlMeas,
  77    Bmp280RawMeasurement,
  78    Bmp280Reading,
  79    Hdc1080Config,
  80    Hdc1080Measurement,
  81    Ina226Config,
  82    Ina226DieId,
  83    Ina226MaskEnable,
  84    Opt3001Config,
  85    Scd4xMeasurement,
  86    Sht3xMeasurement,
  87    Sht3xStatus,
  88    Tmp117Config,
  89)
  90from pamoja._native import bmp280_config_bits as _bmp280_config_bits
  91from pamoja._native import bmp280_config_from_bits as _bmp280_config_from_bits
  92from pamoja._native import bmp280_ctrl_meas_bits as _bmp280_ctrl_meas_bits
  93from pamoja._native import bmp280_ctrl_meas_from_bits as _bmp280_ctrl_meas_from_bits
  94from pamoja._native import bmp280_image_updating as _bmp280_image_updating
  95from pamoja._native import bmp280_measurement_bytes as _bmp280_measurement_bytes
  96from pamoja._native import bmp280_measuring as _bmp280_measuring
  97from pamoja._native import bmp280_oversampling_factor as _bmp280_oversampling_factor
  98from pamoja._native import bmp280_parse_measurement as _bmp280_parse_measurement
  99from pamoja._native import bmp280_pressure_skipped as _bmp280_pressure_skipped
 100from pamoja._native import bmp280_standby_micros as _bmp280_standby_micros
 101from pamoja._native import bmp280_temperature_skipped as _bmp280_temperature_skipped
 102from pamoja._native import hdc1080_celsius as _hdc1080_celsius
 103from pamoja._native import hdc1080_config_from_register as _hdc1080_config_from_register
 104from pamoja._native import hdc1080_config_to_register as _hdc1080_config_to_register
 105from pamoja._native import hdc1080_conversion_time_micros as _hdc1080_conversion_time_micros
 106from pamoja._native import (
 107    hdc1080_humidity_conversion_micros as _hdc1080_humidity_conversion_micros,
 108)
 109from pamoja._native import hdc1080_humidity_register as _hdc1080_humidity_register
 110from pamoja._native import hdc1080_measurement_bytes as _hdc1080_measurement_bytes
 111from pamoja._native import hdc1080_measurement_from_physical as _hdc1080_measurement_from_physical
 112from pamoja._native import hdc1080_milli_celsius as _hdc1080_milli_celsius
 113from pamoja._native import hdc1080_milli_percent as _hdc1080_milli_percent
 114from pamoja._native import hdc1080_parse_measurement as _hdc1080_parse_measurement
 115from pamoja._native import hdc1080_relative_humidity as _hdc1080_relative_humidity
 116from pamoja._native import hdc1080_serial_id as _hdc1080_serial_id
 117from pamoja._native import hdc1080_serial_id_registers as _hdc1080_serial_id_registers
 118from pamoja._native import (
 119    hdc1080_temperature_conversion_micros as _hdc1080_temperature_conversion_micros,
 120)
 121from pamoja._native import hdc1080_temperature_register as _hdc1080_temperature_register
 122from pamoja._native import ina226_active_alert_function as _ina226_active_alert_function
 123from pamoja._native import ina226_address as _ina226_address
 124from pamoja._native import ina226_averaging_samples as _ina226_averaging_samples
 125from pamoja._native import ina226_bus_microvolts as _ina226_bus_microvolts
 126from pamoja._native import ina226_bus_register as _ina226_bus_register
 127from pamoja._native import ina226_bus_volts as _ina226_bus_volts
 128from pamoja._native import ina226_calibration as _ina226_calibration
 129from pamoja._native import ina226_config_from_register as _ina226_config_from_register
 130from pamoja._native import ina226_config_to_register as _ina226_config_to_register
 131from pamoja._native import ina226_conversion_micros as _ina226_conversion_micros
 132from pamoja._native import ina226_current_amps as _ina226_current_amps
 133from pamoja._native import ina226_current_microamps as _ina226_current_microamps
 134from pamoja._native import ina226_current_register as _ina226_current_register
 135from pamoja._native import (
 136    ina226_current_register_from_shunt as _ina226_current_register_from_shunt,
 137)
 138from pamoja._native import ina226_die_id as _ina226_die_id
 139from pamoja._native import ina226_identify as _ina226_identify
 140from pamoja._native import ina226_is_continuous as _ina226_is_continuous
 141from pamoja._native import ina226_mask_enable_from_register as _ina226_mask_enable_from_register
 142from pamoja._native import ina226_mask_enable_to_register as _ina226_mask_enable_to_register
 143from pamoja._native import ina226_measures_bus as _ina226_measures_bus
 144from pamoja._native import ina226_measures_shunt as _ina226_measures_shunt
 145from pamoja._native import (
 146    ina226_minimum_current_lsb_microamps as _ina226_minimum_current_lsb_microamps,
 147)
 148from pamoja._native import ina226_power_microwatts as _ina226_power_microwatts
 149from pamoja._native import ina226_power_register as _ina226_power_register
 150from pamoja._native import (
 151    ina226_power_register_from_current as _ina226_power_register_from_current,
 152)
 153from pamoja._native import ina226_power_watts as _ina226_power_watts
 154from pamoja._native import ina226_shunt_millivolts as _ina226_shunt_millivolts
 155from pamoja._native import ina226_shunt_nanovolts as _ina226_shunt_nanovolts
 156from pamoja._native import ina226_shunt_register as _ina226_shunt_register
 157from pamoja._native import ina226_update_micros as _ina226_update_micros
 158from pamoja._native import opt3001_config_bits as _opt3001_config_bits
 159from pamoja._native import opt3001_config_from_bits as _opt3001_config_from_bits
 160from pamoja._native import opt3001_conversion_millis as _opt3001_conversion_millis
 161from pamoja._native import opt3001_fault_count as _opt3001_fault_count
 162from pamoja._native import opt3001_full_scale_milli_lux as _opt3001_full_scale_milli_lux
 163from pamoja._native import opt3001_is_automatic_range as _opt3001_is_automatic_range
 164from pamoja._native import opt3001_lsb_milli_lux as _opt3001_lsb_milli_lux
 165from pamoja._native import opt3001_lux as _opt3001_lux
 166from pamoja._native import opt3001_milli_lux as _opt3001_milli_lux
 167from pamoja._native import opt3001_raw_from_milli_lux as _opt3001_raw_from_milli_lux
 168from pamoja._native import opt3001_word_from_bytes as _opt3001_word_from_bytes
 169from pamoja._native import opt3001_word_to_bytes as _opt3001_word_to_bytes
 170from pamoja._native import scd4x_allowed_during_measurement as _scd4x_allowed_during_measurement
 171from pamoja._native import scd4x_ambient_pressure_pascals as _scd4x_ambient_pressure_pascals
 172from pamoja._native import scd4x_ambient_pressure_word as _scd4x_ambient_pressure_word
 173from pamoja._native import (
 174    scd4x_automatic_self_calibration_enabled as _scd4x_automatic_self_calibration_enabled,
 175)
 176from pamoja._native import (
 177    scd4x_automatic_self_calibration_word as _scd4x_automatic_self_calibration_word,
 178)
 179from pamoja._native import scd4x_celsius as _scd4x_celsius
 180from pamoja._native import scd4x_command_frame as _scd4x_command_frame
 181from pamoja._native import scd4x_crc as _scd4x_crc
 182from pamoja._native import scd4x_data_ready as _scd4x_data_ready
 183from pamoja._native import (
 184    scd4x_forced_recalibration_correction_ppm as _scd4x_forced_recalibration_correction_ppm,
 185)
 186from pamoja._native import scd4x_forced_recalibration_word as _scd4x_forced_recalibration_word
 187from pamoja._native import scd4x_humidity_milli_percent as _scd4x_humidity_milli_percent
 188from pamoja._native import scd4x_humidity_raw as _scd4x_humidity_raw
 189from pamoja._native import scd4x_max_duration_ms as _scd4x_max_duration_ms
 190from pamoja._native import scd4x_measurement_bytes as _scd4x_measurement_bytes
 191from pamoja._native import scd4x_measurement_from_physical as _scd4x_measurement_from_physical
 192from pamoja._native import scd4x_milli_celsius as _scd4x_milli_celsius
 193from pamoja._native import scd4x_parse_measurement as _scd4x_parse_measurement
 194from pamoja._native import scd4x_relative_humidity_percent as _scd4x_relative_humidity_percent
 195from pamoja._native import scd4x_self_test_passed as _scd4x_self_test_passed
 196from pamoja._native import scd4x_serial_number as _scd4x_serial_number
 197from pamoja._native import scd4x_serial_number_frame as _scd4x_serial_number_frame
 198from pamoja._native import (
 199    scd4x_temperature_offset_milli_celsius as _scd4x_temperature_offset_milli_celsius,
 200)
 201from pamoja._native import scd4x_temperature_offset_word as _scd4x_temperature_offset_word
 202from pamoja._native import scd4x_temperature_raw as _scd4x_temperature_raw
 203from pamoja._native import scd4x_word as _scd4x_word
 204from pamoja._native import scd4x_word_frame as _scd4x_word_frame
 205from pamoja._native import scd4x_write_frame as _scd4x_write_frame
 206from pamoja._native import sht3x_celsius as _sht3x_celsius
 207from pamoja._native import sht3x_crc as _sht3x_crc
 208from pamoja._native import sht3x_fahrenheit as _sht3x_fahrenheit
 209from pamoja._native import (
 210    sht3x_humidity_raw_from_milli_percent as _sht3x_humidity_raw_from_milli_percent,
 211)
 212from pamoja._native import (
 213    sht3x_humidity_raw_from_relative_humidity as _sht3x_humidity_raw_from_relative_humidity,
 214)
 215from pamoja._native import sht3x_interval_micros as _sht3x_interval_micros
 216from pamoja._native import sht3x_max_measurement_micros as _sht3x_max_measurement_micros
 217from pamoja._native import sht3x_measurement_bytes as _sht3x_measurement_bytes
 218from pamoja._native import sht3x_milli_celsius as _sht3x_milli_celsius
 219from pamoja._native import sht3x_milli_fahrenheit as _sht3x_milli_fahrenheit
 220from pamoja._native import sht3x_milli_percent as _sht3x_milli_percent
 221from pamoja._native import sht3x_parse_measurement as _sht3x_parse_measurement
 222from pamoja._native import sht3x_parse_status as _sht3x_parse_status
 223from pamoja._native import sht3x_periodic as _sht3x_periodic
 224from pamoja._native import sht3x_relative_humidity as _sht3x_relative_humidity
 225from pamoja._native import sht3x_single_shot as _sht3x_single_shot
 226from pamoja._native import sht3x_status_bytes as _sht3x_status_bytes
 227from pamoja._native import sht3x_status_from_bits as _sht3x_status_from_bits
 228from pamoja._native import (
 229    sht3x_temperature_raw_from_celsius as _sht3x_temperature_raw_from_celsius,
 230)
 231from pamoja._native import (
 232    sht3x_temperature_raw_from_milli_celsius as _sht3x_temperature_raw_from_milli_celsius,
 233)
 234from pamoja._native import (
 235    sht3x_temperature_raw_from_milli_fahrenheit as _sht3x_temperature_raw_from_milli_fahrenheit,
 236)
 237from pamoja._native import sht3x_typical_measurement_micros as _sht3x_typical_measurement_micros
 238from pamoja._native import sht3x_word as _sht3x_word
 239from pamoja._native import sht3x_word_bytes as _sht3x_word_bytes
 240from pamoja._native import tmp117_averaging_conversions as _tmp117_averaging_conversions
 241from pamoja._native import tmp117_averaging_micros as _tmp117_averaging_micros
 242from pamoja._native import tmp117_celsius as _tmp117_celsius
 243from pamoja._native import tmp117_config_bits as _tmp117_config_bits
 244from pamoja._native import tmp117_config_from_bits as _tmp117_config_from_bits
 245from pamoja._native import tmp117_cycle_micros as _tmp117_cycle_micros
 246from pamoja._native import tmp117_cycle_nominal_micros as _tmp117_cycle_nominal_micros
 247from pamoja._native import tmp117_data_ready as _tmp117_data_ready
 248from pamoja._native import tmp117_device_id as _tmp117_device_id
 249from pamoja._native import tmp117_eeprom_busy as _tmp117_eeprom_busy
 250from pamoja._native import tmp117_eeprom_unlock_busy as _tmp117_eeprom_unlock_busy
 251from pamoja._native import tmp117_high_alert as _tmp117_high_alert
 252from pamoja._native import tmp117_low_alert as _tmp117_low_alert
 253from pamoja._native import tmp117_micro_celsius as _tmp117_micro_celsius
 254from pamoja._native import tmp117_nano_celsius as _tmp117_nano_celsius
 255from pamoja._native import tmp117_raw_from_celsius as _tmp117_raw_from_celsius
 256from pamoja._native import tmp117_raw_from_micro_celsius as _tmp117_raw_from_micro_celsius
 257from pamoja._native import tmp117_revision as _tmp117_revision
 258from pamoja._native import tmp117_temperature_bytes as _tmp117_temperature_bytes
 259from pamoja._native import tmp117_temperature_from_bytes as _tmp117_temperature_from_bytes
 260from pamoja._native import Ads1115 as _NativeAds1115
 261from pamoja._native import Ads1115Sample, Ina219Config, Ina219Reading, Ina226Reading
 262from pamoja._native import Bmp280 as _NativeBmp280
 263from pamoja._native import Ds18b20Thermometer as _NativeDs18b20Thermometer
 264from pamoja._native import Hdc1080 as _NativeHdc1080
 265from pamoja._native import Ina219 as _NativeIna219
 266from pamoja._native import Ina226 as _NativeIna226
 267from pamoja._native import Opt3001 as _NativeOpt3001
 268from pamoja._native import Opt3001Reading, Tmp117Alerts, Tmp117Reading
 269from pamoja._native import Scd4x as _NativeScd4x
 270from pamoja._native import Sht3x as _NativeSht3x
 271from pamoja._native import Tmp117 as _NativeTmp117
 272from pamoja._native import ads1115_conversion_micros as _ads1115_conversion_micros
 273from pamoja._native import ads1115_sim_part as _ads1115_sim_part
 274from pamoja._native import ads1115_sim_reporting as _ads1115_sim_reporting
 275from pamoja._native import bmp280_sim_burst as _bmp280_sim_burst
 276from pamoja._native import bmp280_sim_burst_for as _bmp280_sim_burst_for
 277from pamoja._native import bmp280_sim_calibration as _bmp280_sim_calibration
 278from pamoja._native import bmp280_sim_part as _bmp280_sim_part
 279from pamoja._native import bmp280_sim_reporting as _bmp280_sim_reporting
 280from pamoja._native import ds18b20_parse_w1_slave as _ds18b20_parse_w1_slave
 281from pamoja._native import ds18b20_w1_slave_text as _ds18b20_w1_slave_text
 282from pamoja._native import hdc1080_sim_part as _hdc1080_sim_part
 283from pamoja._native import hdc1080_sim_reporting as _hdc1080_sim_reporting
 284from pamoja._native import ina219_adc_conversion_micros as _ina219_adc_conversion_micros
 285from pamoja._native import ina219_address as _ina219_address
 286from pamoja._native import ina219_config_bits as _ina219_config_bits
 287from pamoja._native import ina219_config_from_bits as _ina219_config_from_bits
 288from pamoja._native import ina219_conversion_micros as _ina219_conversion_micros
 289from pamoja._native import ina219_gain_range_millivolts as _ina219_gain_range_millivolts
 290from pamoja._native import ina219_sim_part as _ina219_sim_part
 291from pamoja._native import ina219_sim_reporting as _ina219_sim_reporting
 292from pamoja._native import ina226_sim_part as _ina226_sim_part
 293from pamoja._native import ina226_sim_reporting as _ina226_sim_reporting
 294from pamoja._native import opt3001_sim_part as _opt3001_sim_part
 295from pamoja._native import opt3001_sim_reporting as _opt3001_sim_reporting
 296from pamoja._native import scd4x_sim_part as _scd4x_sim_part
 297from pamoja._native import scd4x_sim_reporting as _scd4x_sim_reporting
 298from pamoja._native import sht3x_sim_part as _sht3x_sim_part
 299from pamoja._native import sht3x_sim_reporting as _sht3x_sim_reporting
 300from pamoja._native import tmp117_sim_part as _tmp117_sim_part
 301from pamoja._native import tmp117_sim_reporting as _tmp117_sim_reporting
 302
 303__all__ = [
 304    "Ads1115",
 305    "Ads1115Config",
 306    "Ads1115DataRate",
 307    "Ads1115Mux",
 308    "Ads1115Pga",
 309    "Ads1115Sample",
 310    "Bme280",
 311    "Bme280Calibration",
 312    "Bme280Config",
 313    "Bme280CtrlMeas",
 314    "Bme280Filter",
 315    "Bme280Measurement",
 316    "Bme280Mode",
 317    "Bme280Oversampling",
 318    "Bme280Standby",
 319    "Bmp280",
 320    "Bmp280Calibration",
 321    "Bmp280Coefficients",
 322    "Bmp280Config",
 323    "Bmp280CtrlMeas",
 324    "Bmp280Oversampling",
 325    "Bmp280RawMeasurement",
 326    "Bmp280Reading",
 327    "Ds18b20Reading",
 328    "Ds18b20Thermometer",
 329    "Hdc1080",
 330    "Hdc1080Config",
 331    "Hdc1080HumidityResolution",
 332    "Hdc1080Measurement",
 333    "Hdc1080TemperatureResolution",
 334    "Ina219",
 335    "Ina219Adc",
 336    "Ina219BusRange",
 337    "Ina219Config",
 338    "Ina219Gain",
 339    "Ina219Mode",
 340    "Ina219Reading",
 341    "Ina226",
 342    "Ina226AlertFunction",
 343    "Ina226Averaging",
 344    "Ina226Config",
 345    "Ina226ConversionTime",
 346    "Ina226DieId",
 347    "Ina226Mode",
 348    "Ina226MaskEnable",
 349    "Ina226Reading",
 350    "Opt3001",
 351    "Opt3001Config",
 352    "Opt3001ConversionTime",
 353    "Opt3001Reading",
 354    "Scd4x",
 355    "Scd4xMeasurement",
 356    "Sht3x",
 357    "Sht3xMeasurement",
 358    "Sht3xRate",
 359    "Sht3xRepeatability",
 360    "Sht3xStatus",
 361    "Tmp117",
 362    "Tmp117Alerts",
 363    "Tmp117Averaging",
 364    "Tmp117Config",
 365    "Tmp117Reading",
 366    "ads1115",
 367    "bme280",
 368    "bmp280",
 369    "ds18b20",
 370    "hdc1080",
 371    "ina219",
 372    "ina226",
 373    "opt3001",
 374    "scd4x",
 375    "sht3x",
 376    "tmp117",
 377]
 378
 379
 380class Bme280Oversampling(enum.IntEnum):
 381    """How many samples a BME280 measurement averages, as its register code."""
 382
 383    #: The measurement is skipped.
 384    SKIPPED = 0
 385    #: One sample.
 386    X1 = 1
 387    #: Two samples.
 388    X2 = 2
 389    #: Four samples.
 390    X4 = 3
 391    #: Eight samples.
 392    X8 = 4
 393    #: Sixteen samples.
 394    X16 = 5
 395
 396
 397class Bme280Mode(enum.IntEnum):
 398    """A BME280 power mode, as its register code."""
 399
 400    #: No measurements; the power-on default.
 401    SLEEP = 0
 402    #: One measurement, then back to sleep.
 403    FORCED = 1
 404    #: Measurements on a cycle, a standby period apart.
 405    NORMAL = 3
 406
 407
 408class Bme280Filter(enum.IntEnum):
 409    """The IIR filter that smooths a BME280's pressure and temperature, as its code."""
 410
 411    #: No filtering.
 412    OFF = 0
 413    #: Coefficient 2.
 414    X2 = 1
 415    #: Coefficient 4.
 416    X4 = 2
 417    #: Coefficient 8.
 418    X8 = 3
 419    #: Coefficient 16.
 420    X16 = 4
 421
 422
 423class Bme280Standby(enum.IntEnum):
 424    """The period a BME280 in normal mode rests between measurements, as its code."""
 425
 426    #: 0.5 ms.
 427    MS_0_5 = 0
 428    #: 62.5 ms.
 429    MS_62_5 = 1
 430    #: 125 ms.
 431    MS_125 = 2
 432    #: 250 ms.
 433    MS_250 = 3
 434    #: 500 ms.
 435    MS_500 = 4
 436    #: 1000 ms.
 437    MS_1000 = 5
 438    #: 10 ms.
 439    MS_10 = 6
 440    #: 20 ms.
 441    MS_20 = 7
 442
 443
 444class Bmp280Oversampling(enum.IntEnum):
 445    """How many samples a BMP280 measurement averages, as its register code."""
 446
 447    #: The measurement is skipped.
 448    SKIPPED = 0
 449    #: One sample.
 450    X1 = 1
 451    #: Two samples.
 452    X2 = 2
 453    #: Four samples.
 454    X4 = 3
 455    #: Eight samples.
 456    X8 = 4
 457    #: Sixteen samples.
 458    X16 = 5
 459
 460
 461class Tmp117Averaging(enum.IntEnum):
 462    """How many conversions a TMP117 averages into one result, as its register code."""
 463
 464    #: No averaging: each result is one 15.5 ms conversion.
 465    NONE = 0
 466    #: Eight conversions, the factory setting.
 467    X8 = 1
 468    #: Thirty-two conversions.
 469    X32 = 2
 470    #: Sixty-four conversions.
 471    X64 = 3
 472
 473
 474class Opt3001ConversionTime(enum.IntEnum):
 475    """How long an OPT3001 conversion integrates, in milliseconds."""
 476
 477    #: 100 ms, for speed.
 478    MS_100 = 100
 479    #: 800 ms, for resolution; the part's reset setting.
 480    MS_800 = 800
 481
 482
 483class Hdc1080TemperatureResolution(enum.IntEnum):
 484    """An HDC1080 temperature resolution, as its bit count."""
 485
 486    #: 11 bits, 3.65 ms.
 487    BITS_11 = 11
 488    #: 14 bits, 6.35 ms.
 489    BITS_14 = 14
 490
 491
 492class Hdc1080HumidityResolution(enum.IntEnum):
 493    """An HDC1080 humidity resolution, as its bit count."""
 494
 495    #: 8 bits, 2.5 ms.
 496    BITS_8 = 8
 497    #: 11 bits, 3.85 ms.
 498    BITS_11 = 11
 499    #: 14 bits, 6.5 ms.
 500    BITS_14 = 14
 501
 502
 503class Ina219BusRange(enum.IntEnum):
 504    """An INA219 bus-voltage range, as its register code."""
 505
 506    #: 0 to 16 V.
 507    V16 = 0
 508    #: 0 to 32 V, the reset setting.
 509    V32 = 1
 510
 511
 512class Ina219Gain(enum.IntEnum):
 513    """An INA219 shunt gain, by the shunt-voltage range it gives, as its register code."""
 514
 515    #: Gain 1, 40 mV either side of zero.
 516    DIV1 = 0
 517    #: Gain 1/2, 80 mV.
 518    DIV2 = 1
 519    #: Gain 1/4, 160 mV.
 520    DIV4 = 2
 521    #: Gain 1/8, 320 mV, the reset setting.
 522    DIV8 = 3
 523
 524
 525class Ina219Adc(enum.IntEnum):
 526    """An INA219 converter setting: a resolution, or samples averaged at 12 bits."""
 527
 528    #: 9 bits, 84 us.
 529    BITS_9 = 0b0000
 530    #: 10 bits, 148 us.
 531    BITS_10 = 0b0001
 532    #: 11 bits, 276 us.
 533    BITS_11 = 0b0010
 534    #: 12 bits, 532 us, the reset setting.
 535    BITS_12 = 0b0011
 536    #: 2 samples averaged, 1.06 ms.
 537    SAMPLES_2 = 0b1001
 538    #: 4 samples averaged, 2.13 ms.
 539    SAMPLES_4 = 0b1010
 540    #: 8 samples averaged, 4.26 ms.
 541    SAMPLES_8 = 0b1011
 542    #: 16 samples averaged, 8.51 ms.
 543    SAMPLES_16 = 0b1100
 544    #: 32 samples averaged, 17.02 ms.
 545    SAMPLES_32 = 0b1101
 546    #: 64 samples averaged, 34.05 ms.
 547    SAMPLES_64 = 0b1110
 548    #: 128 samples averaged, 68.10 ms.
 549    SAMPLES_128 = 0b1111
 550
 551
 552class Ina219Mode(enum.IntEnum):
 553    """An INA219 operating mode, as its register code."""
 554
 555    #: No conversions, lowest power.
 556    POWER_DOWN = 0
 557    #: One shunt conversion.
 558    SHUNT_TRIGGERED = 1
 559    #: One bus conversion.
 560    BUS_TRIGGERED = 2
 561    #: One shunt and one bus conversion.
 562    SHUNT_AND_BUS_TRIGGERED = 3
 563    #: The converter disabled.
 564    ADC_OFF = 4
 565    #: Shunt conversions back to back.
 566    SHUNT_CONTINUOUS = 5
 567    #: Bus conversions back to back.
 568    BUS_CONTINUOUS = 6
 569    #: Shunt and bus conversions back to back, the reset setting.
 570    SHUNT_AND_BUS_CONTINUOUS = 7
 571
 572
 573class Ina226Averaging(enum.IntEnum):
 574    """How many samples an INA226 folds into each result, as its register code."""
 575
 576    #: Every conversion reported, the reset setting.
 577    SAMPLES_1 = 0
 578    #: 4 samples.
 579    SAMPLES_4 = 1
 580    #: 16 samples.
 581    SAMPLES_16 = 2
 582    #: 64 samples.
 583    SAMPLES_64 = 3
 584    #: 128 samples.
 585    SAMPLES_128 = 4
 586    #: 256 samples.
 587    SAMPLES_256 = 5
 588    #: 512 samples.
 589    SAMPLES_512 = 6
 590    #: 1024 samples.
 591    SAMPLES_1024 = 7
 592
 593
 594class Ina226ConversionTime(enum.IntEnum):
 595    """An INA226 conversion time, for the bus or the shunt voltage, as its register code."""
 596
 597    #: 140 us.
 598    US_140 = 0
 599    #: 204 us.
 600    US_204 = 1
 601    #: 332 us.
 602    US_332 = 2
 603    #: 588 us.
 604    US_588 = 3
 605    #: 1.1 ms, the reset setting.
 606    US_1100 = 4
 607    #: 2.116 ms.
 608    US_2116 = 5
 609    #: 4.156 ms.
 610    US_4156 = 6
 611    #: 8.244 ms.
 612    US_8244 = 7
 613
 614
 615class Ina226Mode(enum.IntEnum):
 616    """An INA226 operating mode, as its register code."""
 617
 618    #: No conversions; the registers stay readable and writable.
 619    POWER_DOWN = 0
 620    #: One shunt conversion.
 621    SHUNT_TRIGGERED = 1
 622    #: One bus conversion.
 623    BUS_TRIGGERED = 2
 624    #: One shunt and one bus conversion.
 625    SHUNT_AND_BUS_TRIGGERED = 3
 626    #: Shunt conversions back to back.
 627    SHUNT_CONTINUOUS = 5
 628    #: Bus conversions back to back.
 629    BUS_CONTINUOUS = 6
 630    #: Shunt and bus conversions back to back, the reset setting.
 631    SHUNT_AND_BUS_CONTINUOUS = 7
 632
 633
 634class Ads1115Mux(enum.IntEnum):
 635    """An ADS1115 input multiplexer setting, as its register code."""
 636
 637    #: AIN0 against AIN1, the reset setting.
 638    AIN0_AIN1 = 0
 639    #: AIN0 against AIN3.
 640    AIN0_AIN3 = 1
 641    #: AIN1 against AIN3.
 642    AIN1_AIN3 = 2
 643    #: AIN2 against AIN3.
 644    AIN2_AIN3 = 3
 645    #: AIN0 against ground.
 646    AIN0_GND = 4
 647    #: AIN1 against ground.
 648    AIN1_GND = 5
 649    #: AIN2 against ground.
 650    AIN2_GND = 6
 651    #: AIN3 against ground.
 652    AIN3_GND = 7
 653
 654
 655class Ads1115Pga(enum.IntEnum):
 656    """An ADS1115 full-scale range, as its register code."""
 657
 658    #: 6.144 V either side of zero.
 659    FSR_6_144 = 0
 660    #: 4.096 V.
 661    FSR_4_096 = 1
 662    #: 2.048 V, the reset setting.
 663    FSR_2_048 = 2
 664    #: 1.024 V.
 665    FSR_1_024 = 3
 666    #: 0.512 V.
 667    FSR_0_512 = 4
 668    #: 0.256 V.
 669    FSR_0_256 = 5
 670
 671
 672class Ads1115DataRate(enum.IntEnum):
 673    """An ADS1115 data rate, as its register code."""
 674
 675    #: 8 samples per second.
 676    SPS_8 = 0
 677    #: 16 samples per second.
 678    SPS_16 = 1
 679    #: 32 samples per second.
 680    SPS_32 = 2
 681    #: 64 samples per second.
 682    SPS_64 = 3
 683    #: 128 samples per second, the reset setting.
 684    SPS_128 = 4
 685    #: 250 samples per second.
 686    SPS_250 = 5
 687    #: 475 samples per second.
 688    SPS_475 = 6
 689    #: 860 samples per second.
 690    SPS_860 = 7
 691
 692
 693class Bme280:
 694    """A Bosch BME280 driven over an :class:`~pamoja.hal.I2cBus`, measuring on demand in
 695    forced mode.
 696
 697    Nothing is sent until :meth:`init` or the first :meth:`measure`. The driver holds its
 698    own share of the bus, and releases the interpreter while the part answers.
 699
 700    >>> from pamoja.hal import I2cBus
 701    >>> bus = I2cBus.simulated([bme280.sim.part(bme280.ADDRESS_PRIMARY)])
 702    >>> sensor = Bme280(bus, bme280.ADDRESS_PRIMARY)
 703    >>> f"{sensor.measure().celsius:.2f}"
 704    '20.44'
 705    """
 706
 707    __slots__ = ("_native",)
 708
 709    def __init__(
 710        self,
 711        bus: I2cBus,
 712        address: int,
 713        *,
 714        temperature: Bme280Oversampling = Bme280Oversampling.X1,
 715        pressure: Bme280Oversampling = Bme280Oversampling.X1,
 716        humidity: Bme280Oversampling = Bme280Oversampling.X1,
 717        filter: Bme280Filter = Bme280Filter.OFF,
 718    ) -> None:
 719        """Make a driver for the part at ``address`` on ``bus``.
 720
 721        :param bus: The bus the part is on.
 722        :param address: ``bme280.ADDRESS_PRIMARY`` with SDO low, or
 723            ``bme280.ADDRESS_SECONDARY`` with SDO high.
 724        :param temperature: The temperature oversampling.
 725        :param pressure: The pressure oversampling.
 726        :param humidity: The humidity oversampling.
 727        :param filter: The IIR filter.
 728        """
 729        self._native = _NativeBme280(
 730            bus._native,
 731            address,
 732            int(temperature),
 733            int(pressure),
 734            int(humidity),
 735            int(filter),
 736        )
 737
 738    def init(self) -> None:
 739        """Reset the part, check it is a BME280, read its calibration, and write the
 740        settings in the order the datasheet requires, leaving the part asleep.
 741
 742        :raises PamojaError: If nothing answers at the address, another part does, or
 743            the calibration never finishes loading.
 744        """
 745        self._native.init()
 746
 747    def measure(self) -> Bme280Measurement:
 748        """Run one forced measurement and compensate it, initializing the part first if
 749        :meth:`init` has not run.
 750
 751        :returns: The reading.
 752        :raises PamojaError: As :meth:`init`, and when the part is still measuring after
 753            the datasheet's time.
 754        """
 755        return self._native.measure()
 756
 757
 758class _Bme280Sim:
 759    """A BME280 that is not there, for a bus with nothing plugged in."""
 760
 761    __slots__ = ()
 762
 763    #: The status a simulated part reports when it is neither measuring nor loading.
 764    STATUS_IDLE = 0x00
 765
 766    def part(self, address: int) -> I2cPart:
 767        """Make a part holding a real BME280's calibration and one measurement it took,
 768        which compensate to 20.44 C, 848.05 hPa, and 44.65 %.
 769
 770        :param address: The address it answers to.
 771        :returns: The part, to put on a simulated bus.
 772        """
 773        return I2cPart._wrap(_bme280_sim_part(address))
 774
 775    def reporting(
 776        self, address: int, celsius: float, hectopascals: float, relative_humidity: float
 777    ) -> I2cPart:
 778        """Make a part that reads what it is asked to, to within what its converter can
 779        represent.
 780
 781        :param address: The address it answers to.
 782        :param celsius: The temperature it reports.
 783        :param hectopascals: The pressure it reports.
 784        :param relative_humidity: The humidity it reports, as a percentage.
 785        :returns: The part, to put on a simulated bus.
 786        """
 787        return I2cPart._wrap(
 788            _bme280_sim_reporting(address, celsius, hectopascals, relative_humidity)
 789        )
 790
 791    def calibration(self) -> bytes:
 792        """The 26-byte temperature and pressure calibration block a simulated part holds."""
 793        return bytes(_bme280_sim_calibration())
 794
 795    def calibration_humidity(self) -> bytes:
 796        """The 7-byte humidity calibration block a simulated part holds."""
 797        return bytes(_bme280_sim_calibration_humidity())
 798
 799    def burst(self) -> bytes:
 800        """The eight data registers a simulated part holds: one measurement a real part
 801        took."""
 802        return bytes(_bme280_sim_burst())
 803
 804    def burst_for(self, celsius: float, hectopascals: float, relative_humidity: float) -> bytes:
 805        """Build the eight data registers that compensate to a reading against the
 806        simulated calibration.
 807
 808        :param celsius: The temperature.
 809        :param hectopascals: The pressure.
 810        :param relative_humidity: The humidity, as a percentage.
 811        :returns: The bytes a burst read would return.
 812        """
 813        return bytes(_bme280_sim_burst_for(celsius, hectopascals, relative_humidity))
 814
 815
 816class _Bme280:
 817    """A Bosch BME280 temperature, pressure, and humidity sensor."""
 818
 819    __slots__ = ()
 820
 821    #: The address a BME280 answers on with its SDO pin low.
 822    ADDRESS_PRIMARY = 0x76
 823    #: The address it answers on with SDO high.
 824    ADDRESS_SECONDARY = 0x77
 825    #: The value its chip-ID register reads, which tells it from a BMP280.
 826    CHIP_ID = 0x60
 827    #: The word written to the reset register to restart the part.
 828    RESET_WORD = 0xB6
 829    #: How long the part takes to start after a reset, in microseconds.
 830    STARTUP_MICROS = 2_000
 831    #: How many bytes the temperature and pressure calibration block holds.
 832    CALIBRATION_TEMP_PRESS_LENGTH = 26
 833    #: How many bytes the humidity calibration block holds.
 834    CALIBRATION_HUMIDITY_LENGTH = 7
 835    #: How many bytes one measurement burst holds.
 836    DATA_LENGTH = 8
 837    #: The chip-ID register.
 838    REGISTER_CHIP_ID = 0xD0
 839    #: The reset register.
 840    REGISTER_RESET = 0xE0
 841    #: The first of the 26 temperature and pressure calibration bytes.
 842    REGISTER_CALIB_TEMP_PRESS = 0x88
 843    #: The first of the 7 humidity calibration bytes.
 844    REGISTER_CALIB_HUMIDITY = 0xE1
 845    #: The humidity control register, ``ctrl_hum``.
 846    REGISTER_CTRL_HUM = 0xF2
 847    #: The status register.
 848    REGISTER_STATUS = 0xF3
 849    #: The measurement control register, ``ctrl_meas``.
 850    REGISTER_CTRL_MEAS = 0xF4
 851    #: The configuration register, ``config``.
 852    REGISTER_CONFIG = 0xF5
 853    #: The first of the 8 data bytes a burst read covers.
 854    REGISTER_DATA = 0xF7
 855
 856    #: The oversampling codes.
 857    Oversampling = Bme280Oversampling
 858    #: The power mode codes.
 859    Mode = Bme280Mode
 860    #: The IIR filter codes.
 861    Filter = Bme280Filter
 862    #: The normal-mode standby codes.
 863    Standby = Bme280Standby
 864
 865    #: A BME280 that is not there, for a bus with nothing plugged in.
 866    sim = _Bme280Sim()
 867
 868    def calibration(self, temp_press: bytes, humidity: bytes) -> Bme280Calibration:
 869        """Read the factory calibration out of the registers, once at start-up.
 870
 871        :param temp_press: The 26-byte temperature and pressure calibration block.
 872        :param humidity: The 7-byte humidity calibration block.
 873        :returns: The calibration, to reuse for every measurement.
 874        :raises ValueError: If either block is the wrong length.
 875        """
 876        return Bme280Calibration(bytes(temp_press), bytes(humidity))
 877
 878    def measuring(self, status: int) -> bool:
 879        """Report whether a status register says a conversion is running.
 880
 881        :param status: The status register.
 882        :returns: Whether a measurement is in progress.
 883        """
 884        return _bme280_measuring(status)
 885
 886    def image_updating(self, status: int) -> bool:
 887        """Report whether a status register says the calibration image is loading.
 888
 889        :param status: The status register.
 890        :returns: Whether the calibration is still being copied.
 891        """
 892        return _bme280_image_updating(status)
 893
 894    def ctrl_meas_bits(self, ctrl: Bme280CtrlMeas) -> int:
 895        """Pack a ``ctrl_meas`` register value.
 896
 897        :param ctrl: The oversampling codes and the power mode.
 898        :returns: The register value to write.
 899        """
 900        return _bme280_ctrl_meas_bits(ctrl)
 901
 902    def ctrl_meas_from_bits(self, bits: int) -> Bme280CtrlMeas:
 903        """Parse a ``ctrl_meas`` register value.
 904
 905        :param bits: The register value, as read from the part.
 906        :returns: The oversampling codes and the power mode.
 907        """
 908        return _bme280_ctrl_meas_from_bits(bits)
 909
 910    def ctrl_hum_bits(self, humidity: int) -> int:
 911        """Pack a ``ctrl_hum`` register value, which takes effect only after the next
 912        ``ctrl_meas`` write.
 913
 914        :param humidity: The humidity oversampling code.
 915        :returns: The register value to write.
 916        """
 917        return _bme280_ctrl_hum_bits(int(humidity))
 918
 919    def ctrl_hum_from_bits(self, bits: int) -> Bme280Oversampling:
 920        """Parse a ``ctrl_hum`` register value.
 921
 922        :param bits: The register value, as read from the part.
 923        :returns: The humidity oversampling.
 924        """
 925        return Bme280Oversampling(_bme280_ctrl_hum_from_bits(bits))
 926
 927    def config_bits(self, config: Bme280Config) -> int:
 928        """Pack a ``config`` register value.
 929
 930        :param config: The standby period, filter, and interface settings.
 931        :returns: The register value to write.
 932        """
 933        return _bme280_config_bits(config)
 934
 935    def config_from_bits(self, bits: int) -> Bme280Config:
 936        """Parse a ``config`` register value.
 937
 938        :param bits: The register value, as read from the part.
 939        :returns: The standby period, filter, and interface settings.
 940        """
 941        return _bme280_config_from_bits(bits)
 942
 943    def oversampling_factor(self, code: int) -> int:
 944        """Return how many samples an oversampling code averages.
 945
 946        :param code: The oversampling code.
 947        :returns: The factor, or 0 when the code skips the measurement.
 948        """
 949        return _bme280_oversampling_factor(int(code))
 950
 951    def standby_micros(self, code: int) -> int:
 952        """Return the standby period a code selects in normal mode.
 953
 954        :param code: The standby code.
 955        :returns: The period in microseconds.
 956        """
 957        return _bme280_standby_micros(int(code))
 958
 959    def filter_coefficient(self, code: int) -> int:
 960        """Return the IIR coefficient a filter code selects.
 961
 962        :param code: The filter code.
 963        :returns: The coefficient, or 0 when the filter is off.
 964        """
 965        return _bme280_filter_coefficient(int(code))
 966
 967    def max_measurement_micros(self, temperature: int, pressure: int, humidity: int) -> int:
 968        """Return the longest one measurement can take, which is how long a driver waits
 969        after forcing one.
 970
 971        :param temperature: The temperature oversampling code.
 972        :param pressure: The pressure oversampling code.
 973        :param humidity: The humidity oversampling code.
 974        :returns: The datasheet's maximum in microseconds.
 975        """
 976        return _bme280_max_measurement_micros(int(temperature), int(pressure), int(humidity))
 977
 978    def typical_measurement_micros(self, temperature: int, pressure: int, humidity: int) -> int:
 979        """Return the typical time one measurement takes.
 980
 981        :param temperature: The temperature oversampling code.
 982        :param pressure: The pressure oversampling code.
 983        :param humidity: The humidity oversampling code.
 984        :returns: The datasheet's typical time in microseconds.
 985        """
 986        return _bme280_typical_measurement_micros(
 987            int(temperature), int(pressure), int(humidity)
 988        )
 989
 990
 991class _Ds18b20:
 992    """A Maxim DS18B20 1-Wire thermometer."""
 993
 994    __slots__ = ()
 995
 996    #: The 1-Wire family code that identifies a DS18B20 on the bus.
 997    FAMILY_CODE = 0x28
 998
 999    def parse_scratchpad(self, data: bytes) -> Ds18b20Reading:
1000        """Parse and CRC-check a nine-byte scratchpad.
1001
1002        :param data: The scratchpad as the device sent it, the ninth byte its CRC.
1003        :returns: The decoded reading.
1004        :raises PamojaError: If the CRC does not match, which means the read was
1005            corrupted on the bus and should be repeated.
1006        """
1007        return _ds18b20_parse_scratchpad(bytes(data))
1008
1009    def build_scratchpad(
1010        self, celsius: float, resolution_bits: int, alarm_high: int, alarm_low: int
1011    ) -> bytes:
1012        """Build the nine bytes a part in the given state puts on the bus.
1013
1014        This is the inverse of :meth:`parse_scratchpad`, so a node can be written and
1015        tested against what a thermometer sends without one attached.
1016
1017        :param celsius: The temperature the part is reading.
1018        :param resolution_bits: The resolution it is configured for, 9 to 12.
1019        :param alarm_high: The high alarm threshold in whole degrees Celsius.
1020        :param alarm_low: The low alarm threshold in whole degrees Celsius.
1021        :returns: The nine scratchpad bytes in transmission order, CRC last.
1022        :raises PamojaError: If the resolution is not 9, 10, 11, or 12 bits.
1023        """
1024        return bytes(
1025            _ds18b20_build_scratchpad(celsius, resolution_bits, alarm_high, alarm_low)
1026        )
1027
1028    def crc8(self, data: bytes) -> int:
1029        """Compute the Maxim CRC-8 a 1-Wire device checks its own bytes with.
1030
1031        :param data: The bytes the checksum covers.
1032        :returns: The checksum.
1033        """
1034        return _ds18b20_crc8(bytes(data))
1035
1036    def micro_celsius(self, raw: int) -> int:
1037        """Convert a raw temperature register to micro-degrees Celsius.
1038
1039        :param raw: The 16-bit two's-complement register.
1040        :returns: The temperature, exact in integer arithmetic.
1041        """
1042        return _ds18b20_micro_celsius(raw)
1043
1044    def celsius(self, raw: int) -> float:
1045        """Convert a raw temperature register to degrees Celsius.
1046
1047        :param raw: The 16-bit two's-complement register.
1048        :returns: The temperature.
1049        """
1050        return _ds18b20_celsius(raw)
1051
1052    def config_byte(self, bits: int) -> int:
1053        """Return the configuration byte that selects a resolution.
1054
1055        :param bits: The resolution in bits: 9, 10, 11, or 12.
1056        :returns: The byte to write to the configuration register.
1057        :raises ValueError: If the resolution is not one the part offers.
1058        """
1059        return _ds18b20_config_byte(bits)
1060
1061    def resolution_bits(self, config_byte: int) -> int:
1062        """Return the resolution a configuration byte selects.
1063
1064        :param config_byte: The byte read from the configuration register.
1065        :returns: The resolution in bits.
1066        """
1067        return _ds18b20_resolution_bits(config_byte)
1068
1069    def step_micro_celsius(self, bits: int) -> int:
1070        """Return the temperature step a resolution resolves.
1071
1072        :param bits: The resolution in bits.
1073        :returns: The step in micro-degrees Celsius.
1074        :raises ValueError: If the resolution is not one the part offers.
1075        """
1076        return _ds18b20_step_micro_celsius(bits)
1077
1078    def max_conversion_micros(self, bits: int) -> int:
1079        """Return how long a conversion may take at a resolution.
1080
1081        :param bits: The resolution in bits.
1082        :returns: The datasheet's worst case, in microseconds.
1083        :raises ValueError: If the resolution is not one the part offers.
1084        """
1085        return _ds18b20_max_conversion_micros(bits)
1086
1087    def parse_w1_slave(self, text: str) -> Ds18b20Reading:
1088        """Decode the text the Linux kernel's ``w1_therm`` driver serves for a thermometer:
1089        the scratchpad in hex with the kernel's checksum verdict, then the temperature.
1090
1091        :param text: The ``w1_slave`` file's contents.
1092        :returns: The reading, its CRC checked here as well.
1093        :raises PamojaError: If the kernel or this decoder rejects the CRC, or the text is
1094            not in the driver's format.
1095        """
1096        return _ds18b20_parse_w1_slave(text)
1097
1098    def w1_slave_text(self, data: bytes) -> str:
1099        """Render the text the Linux kernel's ``w1_therm`` driver serves for a scratchpad
1100        it read cleanly, the inverse of :meth:`parse_w1_slave`: the bytes with the CRC the
1101        kernel computed and ``YES``, then the bytes again with ``t=`` and the temperature
1102        in millidegrees.
1103
1104        :param data: The nine scratchpad bytes, the ninth their CRC.
1105        :returns: The ``w1_slave`` file's two lines.
1106        :raises ValueError: If the bytes are not nine.
1107        :raises PamojaError: If the CRC does not match.
1108        """
1109        return _ds18b20_w1_slave_text(bytes(data))
1110
1111
1112class _Ina219Sim:
1113    """An INA219 that is not there, for a bus with nothing plugged in.
1114
1115    A monitor's current and power registers count in steps the calibration sets, so
1116    :meth:`reporting` takes the same shunt and largest current a driver is given.
1117    """
1118
1119    __slots__ = ()
1120
1121    #: The shunt :meth:`part` sits across, in milliohms: the common breakout's.
1122    SHUNT_MILLIOHMS = 100
1123    #: The largest current :meth:`part` is sized for, in microamps.
1124    MAX_MICROAMPS = 3_200_000
1125    #: The bus voltage :meth:`part` reports, in millivolts.
1126    BUS_MILLIVOLTS = 12_000
1127    #: The current :meth:`part` reports, in microamps.
1128    MICROAMPS = 500_000
1129
1130    def part(self, address: int) -> WordPart:
1131        """Make a part carrying 500 mA at 12 V through the shunt a driver starts with.
1132
1133        :param address: The address it answers to.
1134        :returns: The part, to put on a simulated bus.
1135        """
1136        return WordPart._wrap(_ina219_sim_part(address))
1137
1138    def reporting(
1139        self,
1140        address: int,
1141        shunt_milliohms: int,
1142        max_microamps: int,
1143        bus_millivolts: int,
1144        microamps: int,
1145    ) -> WordPart:
1146        """Make a part that reads what it is asked to, on the steps its registers count
1147        in: 4 mV of bus, 10 uV of shunt, and the calibration's current step.
1148
1149        :param address: The address it answers to.
1150        :param shunt_milliohms: The shunt, as the driver is given it.
1151        :param max_microamps: The largest current, as the driver is given it.
1152        :param bus_millivolts: The bus voltage it reports.
1153        :param microamps: The current it reports; negative flows the other way.
1154        :returns: The part, to put on a simulated bus.
1155        """
1156        return WordPart._wrap(
1157            _ina219_sim_reporting(
1158                address, shunt_milliohms, max_microamps, bus_millivolts, microamps
1159            )
1160        )
1161
1162
1163class _Ina219:
1164    """A TI INA219 current, voltage, and power monitor."""
1165
1166    __slots__ = ()
1167
1168    #: The address with A1 and A0 tied to ground; the pins add to it.
1169    BASE_ADDRESS = 0x40
1170    #: An address pin tied to GND, as the code :meth:`address` takes.
1171    PIN_GROUND = 0
1172    #: An address pin tied to VS+.
1173    PIN_SUPPLY = 1
1174    #: An address pin tied to SDA.
1175    PIN_SDA = 2
1176    #: An address pin tied to SCL.
1177    PIN_SCL = 3
1178    #: The configuration register's power-on value.
1179    CONFIG_RESET = 0x399F
1180    #: The configuration register: range, gain, converter settings, and mode.
1181    REGISTER_CONFIGURATION = 0x00
1182    #: The shunt voltage, 10 uV per count.
1183    REGISTER_SHUNT_VOLTAGE = 0x01
1184    #: The bus voltage in bits 15:3, 4 mV per count, with two flags below.
1185    REGISTER_BUS_VOLTAGE = 0x02
1186    #: The power, scaled by the calibration.
1187    REGISTER_POWER = 0x03
1188    #: The current, scaled by the calibration.
1189    REGISTER_CURRENT = 0x04
1190    #: The calibration, which sets the current and power scale.
1191    REGISTER_CALIBRATION = 0x05
1192
1193    #: The bus-voltage range codes.
1194    BusRange = Ina219BusRange
1195    #: The shunt gain codes.
1196    Gain = Ina219Gain
1197    #: The converter codes.
1198    Adc = Ina219Adc
1199    #: The operating-mode codes.
1200    Mode = Ina219Mode
1201    #: An INA219 that is not there, for a bus with nothing plugged in.
1202    sim = _Ina219Sim()
1203
1204    def address(self, a1: int, a0: int) -> int:
1205        """Return the 7-bit address the A1 and A0 pins select, from Table 1 of the
1206        datasheet.
1207
1208        :param a1: What the A1 pin is tied to, one of the ``PIN_`` codes.
1209        :param a0: What the A0 pin is tied to.
1210        :returns: The address, 0x40 to 0x4F.
1211        :raises ValueError: If either pin code is not 0, 1, 2, or 3.
1212        """
1213        return _ina219_address(a1, a0)
1214
1215    def config_bits(self, config: Ina219Config) -> int:
1216        """Assemble the configuration register value.
1217
1218        :param config: The range, gain, converter, and mode codes.
1219        :returns: The register value to write.
1220        """
1221        return _ina219_config_bits(config)
1222
1223    def config_from_bits(self, bits: int) -> Ina219Config:
1224        """Parse a configuration register value.
1225
1226        :param bits: The register value, as read from the part.
1227        :returns: The settings. Every value decodes.
1228        """
1229        return _ina219_config_from_bits(bits)
1230
1231    def conversion_micros(self, config: Ina219Config) -> int:
1232        """Return how long one conversion cycle takes: the shunt and bus conversions the
1233        mode runs, one after the other.
1234
1235        :param config: The settings.
1236        :returns: The time in microseconds.
1237        """
1238        return _ina219_conversion_micros(config)
1239
1240    def adc_conversion_micros(self, adc: Ina219Adc) -> int:
1241        """Return how long one conversion takes at a converter setting.
1242
1243        :param adc: The setting.
1244        :returns: The time in microseconds, from the datasheet's table.
1245        """
1246        return _ina219_adc_conversion_micros(int(adc))
1247
1248    def gain_range_millivolts(self, gain: Ina219Gain) -> int:
1249        """Return the shunt-voltage range a gain selects.
1250
1251        :param gain: The gain.
1252        :returns: The range in millivolts either side of zero.
1253        """
1254        return _ina219_gain_range_millivolts(int(gain))
1255
1256    def calibration(self, current_lsb_microamps: int, shunt_milliohms: int) -> int:
1257        """Compute the calibration register for a shunt and current resolution.
1258
1259        :param current_lsb_microamps: The microamps per count the current register
1260            should carry.
1261        :param shunt_milliohms: The shunt resistor value.
1262        :returns: The register value to write.
1263        """
1264        return _ina219_calibration(current_lsb_microamps, shunt_milliohms)
1265
1266    def minimum_current_lsb_microamps(self, max_expected_microamps: int) -> int:
1267        """Return the smallest current resolution that still covers a maximum.
1268
1269        :param max_expected_microamps: The largest current the application measures.
1270        :returns: The minimum current LSB in microamps.
1271        """
1272        return _ina219_minimum_current_lsb_microamps(max_expected_microamps)
1273
1274    def shunt_register(self, microvolts: int) -> int:
1275        """Build the shunt-voltage register a monitor reports for a shunt voltage.
1276
1277        The inverse of :meth:`shunt_microvolts`, so a node can be written and tested
1278        against what a monitor sends without one attached.
1279
1280        :param microvolts: The shunt voltage in microvolts.
1281        :returns: The signed register value, at 10 uV per count.
1282        """
1283        return _ina219_shunt_register(microvolts)
1284
1285    def bus_register(self, millivolts: int) -> int:
1286        """Build the bus-voltage register a monitor reports for a bus voltage.
1287
1288        :param millivolts: The bus voltage in millivolts.
1289        :returns: The register value, with the conversion-ready flag set.
1290        """
1291        return _ina219_bus_register(millivolts)
1292
1293    def current_register(self, microamps: int, current_lsb_microamps: int) -> int:
1294        """Build the current register a monitor reports for a current.
1295
1296        :param microamps: The current in microamps.
1297        :param current_lsb_microamps: The current LSB the calibration was set for.
1298        :returns: The signed register value.
1299        """
1300        return _ina219_current_register(microamps, current_lsb_microamps)
1301
1302    def power_register(self, microwatts: int, current_lsb_microamps: int) -> int:
1303        """Build the power register a monitor reports for a power.
1304
1305        :param microwatts: The power in microwatts.
1306        :param current_lsb_microamps: The current LSB the calibration was set for.
1307        :returns: The register value.
1308        """
1309        return _ina219_power_register(microwatts, current_lsb_microamps)
1310
1311    def shunt_microvolts(self, raw: int) -> int:
1312        """Convert a raw shunt-voltage register to microvolts.
1313
1314        :param raw: The signed register value.
1315        :returns: The shunt voltage.
1316        """
1317        return _ina219_shunt_microvolts(raw)
1318
1319    def bus_millivolts(self, raw: int) -> int:
1320        """Convert a raw bus-voltage register to millivolts.
1321
1322        :param raw: The register value.
1323        :returns: The bus voltage.
1324        """
1325        return _ina219_bus_millivolts(raw)
1326
1327    def conversion_ready(self, raw: int) -> bool:
1328        """Report whether a bus-voltage register says a conversion is ready.
1329
1330        :param raw: The register value.
1331        :returns: Whether the conversion-ready flag is set.
1332        """
1333        return _ina219_conversion_ready(raw)
1334
1335    def math_overflow(self, raw: int) -> bool:
1336        """Report whether a bus-voltage register flags a math overflow.
1337
1338        :param raw: The register value.
1339        :returns: Whether the current and power readings are meaningless, which
1340            means the calibration needs revisiting.
1341        """
1342        return _ina219_math_overflow(raw)
1343
1344    def current_microamps(self, raw: int, current_lsb_microamps: int) -> int:
1345        """Convert a raw current register to microamps.
1346
1347        :param raw: The signed register value.
1348        :param current_lsb_microamps: The resolution the calibration selected.
1349        :returns: The current.
1350        """
1351        return _ina219_current_microamps(raw, current_lsb_microamps)
1352
1353    def power_microwatts(self, raw: int, current_lsb_microamps: int) -> int:
1354        """Convert a raw power register to microwatts.
1355
1356        :param raw: The register value.
1357        :param current_lsb_microamps: The resolution the calibration selected.
1358        :returns: The power. The power LSB is fixed at twenty times the current LSB.
1359        """
1360        return _ina219_power_microwatts(raw, current_lsb_microamps)
1361
1362
1363class _Ads1115Sim:
1364    """An ADS1115 that is not there, for a bus with nothing plugged in.
1365
1366    A conversion comes back as a count of the range the gain selects, so :meth:`reporting`
1367    takes the same gain a driver is given.
1368    """
1369
1370    __slots__ = ()
1371
1372    #: The voltage :meth:`part` reports: half a 3.3 V supply.
1373    VOLTS = 1.65
1374
1375    def part(self, address: int) -> WordPart:
1376        """Make a part reading :attr:`VOLTS` at the range a driver starts with.
1377
1378        :param address: The address it answers to.
1379        :returns: The part, to put on a simulated bus.
1380        """
1381        return WordPart._wrap(_ads1115_sim_part(address))
1382
1383    def reporting(self, address: int, pga: Ads1115Pga, volts: float) -> WordPart:
1384        """Make a part that reads what it is asked to, on the nearest of the 32768 steps
1385        either side of zero the range divides into.
1386
1387        :param address: The address it answers to.
1388        :param pga: The range the driver converts at.
1389        :param volts: The voltage it reports, held to the range.
1390        :returns: The part, to put on a simulated bus.
1391        """
1392        return WordPart._wrap(_ads1115_sim_reporting(address, int(pga), volts))
1393
1394
1395class _Ads1115:
1396    """A TI ADS1115 16-bit analog-to-digital converter."""
1397
1398    __slots__ = ()
1399
1400    #: The address with ADDR tied to ground.
1401    ADDRESS_GND = 0x48
1402    #: The address with ADDR tied to VDD.
1403    ADDRESS_VDD = 0x49
1404    #: The address with ADDR tied to SDA.
1405    ADDRESS_SDA = 0x4A
1406    #: The address with ADDR tied to SCL.
1407    ADDRESS_SCL = 0x4B
1408    #: The conversion register.
1409    REGISTER_CONVERSION = 0x00
1410    #: The configuration register.
1411    REGISTER_CONFIG = 0x01
1412    #: The comparator's low threshold register.
1413    REGISTER_LO_THRESH = 0x02
1414    #: The comparator's high threshold register.
1415    REGISTER_HI_THRESH = 0x03
1416
1417    #: The input multiplexer codes.
1418    Mux = Ads1115Mux
1419    #: The full-scale range codes.
1420    Pga = Ads1115Pga
1421    #: The data-rate codes.
1422    DataRate = Ads1115DataRate
1423    #: An ADS1115 that is not there, for a bus with nothing plugged in.
1424    sim = _Ads1115Sim()
1425
1426    def conversion_micros(self, data_rate: Ads1115DataRate) -> int:
1427        """Return how long a conversion takes at a data rate: one period plus the
1428        datasheet's ten percent rate variation.
1429
1430        :param data_rate: The data rate.
1431        :returns: The time in microseconds.
1432        """
1433        return _ads1115_conversion_micros(int(data_rate))
1434
1435    #: The value the configuration register reads after a reset.
1436    CONFIG_RESET = 0x8583
1437
1438    def config_bits(self, config: Ads1115Config) -> int:
1439        """Assemble the 16-bit configuration register value.
1440
1441        :param config: The settings to encode.
1442        :returns: The register value to write, most significant bit first.
1443        """
1444        return _ads1115_config_bits(config)
1445
1446    def config_from_bits(self, bits: int) -> Ads1115Config:
1447        """Parse a 16-bit configuration register value.
1448
1449        :param bits: The register value, as read from the device.
1450        :returns: The decoded settings. Every value decodes, so this never raises.
1451        """
1452        return _ads1115_config_from_bits(bits)
1453
1454    def full_scale_microvolts(self, pga: int) -> int:
1455        """Return the full-scale range a gain code selects.
1456
1457        :param pga: The gain code, 0 to 7.
1458        :returns: The full scale in microvolts.
1459        """
1460        return _ads1115_full_scale_microvolts(pga)
1461
1462    def samples_per_second(self, data_rate: int) -> int:
1463        """Return the sample rate a data-rate code selects.
1464
1465        :param data_rate: The data-rate code, 0 to 7.
1466        :returns: The rate in samples per second.
1467        """
1468        return _ads1115_samples_per_second(data_rate)
1469
1470    def to_nanovolts(self, pga: int, raw: int) -> int:
1471        """Convert a raw conversion result to nanovolts.
1472
1473        :param pga: The gain the conversion was taken at.
1474        :param raw: The signed conversion register value.
1475        :returns: The measured voltage, exact at every gain setting.
1476        """
1477        return _ads1115_to_nanovolts(pga, raw)
1478
1479    def to_volts(self, pga: int, raw: int) -> float:
1480        """Convert a raw conversion result to volts.
1481
1482        :param pga: The gain the conversion was taken at.
1483        :param raw: The signed conversion register value.
1484        :returns: The measured voltage.
1485        """
1486        return _ads1115_to_volts(pga, raw)
1487
1488
1489class Sht3xRepeatability(str, enum.Enum):
1490    """How hard an SHT3x works at one measurement, traded against time and power."""
1491
1492    #: The fastest and least precise setting.
1493    LOW = "Low"
1494    #: The middle setting.
1495    MEDIUM = "Medium"
1496    #: The slowest and most precise setting.
1497    HIGH = "High"
1498
1499
1500class Sht3xRate(str, enum.Enum):
1501    """How often an SHT3x in periodic mode takes a measurement."""
1502
1503    #: One measurement every two seconds.
1504    HALF_MPS = "HalfMps"
1505    #: One measurement per second.
1506    ONE_MPS = "OneMps"
1507    #: Two measurements per second.
1508    TWO_MPS = "TwoMps"
1509    #: Four measurements per second.
1510    FOUR_MPS = "FourMps"
1511    #: Ten measurements per second.
1512    TEN_MPS = "TenMps"
1513
1514
1515class Ina226AlertFunction(str, enum.Enum):
1516    """The limit comparison an INA226 alert pin responds to."""
1517
1518    #: The shunt voltage rose above the alert limit.
1519    SHUNT_OVER_LIMIT = "ShuntOverLimit"
1520    #: The shunt voltage fell below the alert limit.
1521    SHUNT_UNDER_LIMIT = "ShuntUnderLimit"
1522    #: The bus voltage rose above the alert limit.
1523    BUS_OVER_LIMIT = "BusOverLimit"
1524    #: The bus voltage fell below the alert limit.
1525    BUS_UNDER_LIMIT = "BusUnderLimit"
1526    #: The power rose above the alert limit.
1527    POWER_OVER_LIMIT = "PowerOverLimit"
1528
1529
1530class _Bmp280Sim:
1531    """A BMP280 that is not there, for a bus with nothing plugged in.
1532
1533    A BMP280 is a BME280 without humidity, so :meth:`part` holds the temperature and
1534    pressure half of a real part and reads 20.44 C and 848.05 hPa.
1535    """
1536
1537    __slots__ = ()
1538
1539    #: The status a simulated part reports when it is neither measuring nor loading.
1540    STATUS_IDLE = 0x00
1541
1542    def part(self, address: int) -> I2cPart:
1543        """Make a part holding a real part's trimming and one measurement it took.
1544
1545        :param address: The address it answers to.
1546        :returns: The part, to put on a simulated bus.
1547        """
1548        return I2cPart._wrap(_bmp280_sim_part(address))
1549
1550    def reporting(self, address: int, celsius: float, hectopascals: float) -> I2cPart:
1551        """Make a part that reads what it is asked to, within a hundredth of a degree and
1552        of a hectopascal.
1553
1554        :param address: The address it answers to.
1555        :param celsius: The temperature it reports.
1556        :param hectopascals: The pressure it reports.
1557        :returns: The part, to put on a simulated bus.
1558        """
1559        return I2cPart._wrap(_bmp280_sim_reporting(address, celsius, hectopascals))
1560
1561    def calibration(self) -> bytes:
1562        """The 24 trimming bytes a simulated part holds."""
1563        return bytes(_bmp280_sim_calibration())
1564
1565    def burst(self) -> bytes:
1566        """The six data registers a simulated part holds: one measurement a real part
1567        took."""
1568        return bytes(_bmp280_sim_burst())
1569
1570    def burst_for(self, celsius: float, hectopascals: float) -> bytes:
1571        """Build the six data registers that compensate to a reading against the simulated
1572        trimming.
1573
1574        :param celsius: The temperature.
1575        :param hectopascals: The pressure.
1576        :returns: The bytes a burst read would return.
1577        """
1578        return bytes(_bmp280_sim_burst_for(celsius, hectopascals))
1579
1580
1581class _Bmp280:
1582    """A Bosch BMP280 pressure and temperature sensor, the BME280 without humidity."""
1583
1584    __slots__ = ()
1585
1586    #: The oversampling codes.
1587    Oversampling = Bmp280Oversampling
1588    #: A BMP280 that is not there, for a bus with nothing plugged in.
1589    sim = _Bmp280Sim()
1590
1591    #: The address a BMP280 answers on with its SDO pin low.
1592    ADDRESS_PRIMARY = 0x76
1593    #: The address it answers on with SDO high.
1594    ADDRESS_SECONDARY = 0x77
1595    #: The value its chip-ID register reads, which confirms the part.
1596    CHIP_ID = 0x58
1597    #: The word written to the reset register to restart the part.
1598    RESET_WORD = 0xB6
1599    #: The raw output a channel reports when its measurement is switched off.
1600    SKIPPED_OUTPUT = 0x80000
1601    #: How many bytes the calibration block holds.
1602    CALIBRATION_LENGTH = 24
1603    #: How many bytes one measurement burst holds.
1604    DATA_LENGTH = 6
1605    #: The first of the 24 calibration bytes.
1606    REGISTER_CALIBRATION = 0x88
1607    #: The chip-ID register.
1608    REGISTER_CHIP_ID = 0xD0
1609    #: The reset register.
1610    REGISTER_RESET = 0xE0
1611    #: The status register.
1612    REGISTER_STATUS = 0xF3
1613    #: The measurement-control register.
1614    REGISTER_CTRL_MEAS = 0xF4
1615    #: The configuration register.
1616    REGISTER_CONFIG = 0xF5
1617    #: The first of the six data bytes.
1618    REGISTER_DATA = 0xF7
1619
1620    def calibration(self, data: bytes) -> Bmp280Calibration:
1621        """Read the factory calibration out of the registers, once at start-up.
1622
1623        :param data: The 24-byte calibration block.
1624        :returns: The calibration, to reuse for every measurement.
1625        :raises ValueError: If the block is the wrong length.
1626        """
1627        return Bmp280Calibration(bytes(data))
1628
1629    def parse_measurement(self, data: bytes) -> Bmp280RawMeasurement:
1630        """Split a six-byte data read into its two uncompensated outputs.
1631
1632        :param data: The six data registers in read order.
1633        :returns: The raw pressure and temperature, before compensation.
1634        :raises ValueError: If the read is the wrong length.
1635        """
1636        return _bmp280_parse_measurement(bytes(data))
1637
1638    def measurement_bytes(self, pressure: int, temperature: int) -> bytes:
1639        """Build the six data-register bytes a part reports for two raw outputs.
1640
1641        The inverse of :meth:`parse_measurement`, so a node can be written and tested
1642        against what a sensor sends without one attached.
1643
1644        :param pressure: The 20-bit uncompensated pressure.
1645        :param temperature: The 20-bit uncompensated temperature.
1646        :returns: The six bytes in read order.
1647        """
1648        return bytes(_bmp280_measurement_bytes(pressure, temperature))
1649
1650    def pressure_skipped(self, pressure: int) -> bool:
1651        """Report whether a raw pressure says the measurement is switched off.
1652
1653        :param pressure: The 20-bit uncompensated pressure.
1654        :returns: Whether the channel's oversampling is set to skip.
1655        """
1656        return _bmp280_pressure_skipped(pressure)
1657
1658    def temperature_skipped(self, temperature: int) -> bool:
1659        """Report whether a raw temperature says the measurement is switched off.
1660
1661        :param temperature: The 20-bit uncompensated temperature.
1662        :returns: Whether the channel's oversampling is set to skip.
1663        """
1664        return _bmp280_temperature_skipped(temperature)
1665
1666    def measuring(self, status: int) -> bool:
1667        """Report whether a status register says a conversion is running.
1668
1669        :param status: The status register.
1670        :returns: Whether a measurement is in progress.
1671        """
1672        return _bmp280_measuring(status)
1673
1674    def image_updating(self, status: int) -> bool:
1675        """Report whether a status register says the calibration image is loading.
1676
1677        :param status: The status register.
1678        :returns: Whether the coefficients are still being copied from NVM.
1679        """
1680        return _bmp280_image_updating(status)
1681
1682    def ctrl_meas_bits(self, ctrl: Bmp280CtrlMeas) -> int:
1683        """Pack a measurement-control register value.
1684
1685        :param ctrl: The oversampling settings and power mode.
1686        :returns: The byte to write.
1687        """
1688        return _bmp280_ctrl_meas_bits(ctrl)
1689
1690    def ctrl_meas_from_bits(self, bits: int) -> Bmp280CtrlMeas:
1691        """Parse a measurement-control register value.
1692
1693        :param bits: The byte read from the device.
1694        :returns: The decoded settings.
1695        """
1696        return _bmp280_ctrl_meas_from_bits(bits)
1697
1698    def config_bits(self, config: Bmp280Config) -> int:
1699        """Pack a configuration register value.
1700
1701        :param config: The standby, filter, and interface settings.
1702        :returns: The byte to write.
1703        """
1704        return _bmp280_config_bits(config)
1705
1706    def config_from_bits(self, bits: int) -> Bmp280Config:
1707        """Parse a configuration register value.
1708
1709        :param bits: The byte read from the device.
1710        :returns: The decoded settings.
1711        """
1712        return _bmp280_config_from_bits(bits)
1713
1714    def oversampling_factor(self, code: int) -> int:
1715        """Return how many samples an oversampling code averages.
1716
1717        :param code: The oversampling code, 0 to 5.
1718        :returns: The sample count, or 0 when the measurement is skipped.
1719        """
1720        return _bmp280_oversampling_factor(code)
1721
1722    def standby_micros(self, code: int) -> int:
1723        """Return the normal-mode standby period a code selects.
1724
1725        :param code: The standby code, 0 to 7.
1726        :returns: The period in microseconds.
1727        """
1728        return _bmp280_standby_micros(code)
1729
1730
1731class _Sht3xSim:
1732    """An SHT3x that is not there, for a bus with nothing plugged in.
1733
1734    It answers every single-shot command and a periodic fetch with the reading and its
1735    checksums, and the status command with the status a part reports after a reset.
1736    """
1737
1738    __slots__ = ()
1739
1740    #: The temperature :meth:`part` reports.
1741    CELSIUS = 22.5
1742    #: The relative humidity :meth:`part` reports, as a percentage.
1743    RELATIVE_HUMIDITY = 45.0
1744
1745    def part(self, address: int) -> CommandPart:
1746        """Make a part reading :attr:`CELSIUS` and :attr:`RELATIVE_HUMIDITY`.
1747
1748        :param address: The address it answers to.
1749        :returns: The part, to put on a simulated bus.
1750        """
1751        return CommandPart._wrap(_sht3x_sim_part(address))
1752
1753    def reporting(self, address: int, celsius: float, relative_humidity: float) -> CommandPart:
1754        """Make a part that reads what it is asked to, within three thousandths of a degree
1755        and two thousandths of a percent.
1756
1757        :param address: The address it answers to.
1758        :param celsius: The temperature it reports.
1759        :param relative_humidity: The humidity it reports, as a percentage.
1760        :returns: The part, to put on a simulated bus.
1761        """
1762        return CommandPart._wrap(_sht3x_sim_reporting(address, celsius, relative_humidity))
1763
1764
1765class _Sht3x:
1766    """A Sensirion SHT30, SHT31, or SHT35 temperature and humidity sensor."""
1767
1768    __slots__ = ()
1769
1770    #: An SHT3x that is not there, for a bus with nothing plugged in.
1771    sim = _Sht3xSim()
1772
1773    #: The address the part answers on with its ADDR pin low.
1774    ADDRESS_A = 0x44
1775    #: The address it answers on with ADDR high.
1776    ADDRESS_B = 0x45
1777    #: The shortest gap the datasheet allows between two commands, in microseconds.
1778    MIN_COMMAND_GAP_MICROS = 1_000
1779    #: The status word the part powers up with.
1780    STATUS_DEFAULT = 0x8010
1781    #: Single shot, high repeatability, holding the clock until the result is ready.
1782    COMMAND_SINGLE_SHOT_HIGH_STRETCH = 0x2C06
1783    #: Single shot, medium repeatability, with clock stretching.
1784    COMMAND_SINGLE_SHOT_MEDIUM_STRETCH = 0x2C0D
1785    #: Single shot, low repeatability, with clock stretching.
1786    COMMAND_SINGLE_SHOT_LOW_STRETCH = 0x2C10
1787    #: Single shot, high repeatability, polled rather than stretched.
1788    COMMAND_SINGLE_SHOT_HIGH = 0x2400
1789    #: Single shot, medium repeatability, polled.
1790    COMMAND_SINGLE_SHOT_MEDIUM = 0x240B
1791    #: Single shot, low repeatability, polled.
1792    COMMAND_SINGLE_SHOT_LOW = 0x2416
1793    #: Periodic at one measurement every two seconds, high repeatability.
1794    COMMAND_PERIODIC_HALF_MPS_HIGH = 0x2032
1795    #: Periodic at one measurement every two seconds, medium repeatability.
1796    COMMAND_PERIODIC_HALF_MPS_MEDIUM = 0x2024
1797    #: Periodic at one measurement every two seconds, low repeatability.
1798    COMMAND_PERIODIC_HALF_MPS_LOW = 0x202F
1799    #: Periodic at one measurement per second, high repeatability.
1800    COMMAND_PERIODIC_ONE_MPS_HIGH = 0x2130
1801    #: Periodic at one measurement per second, medium repeatability.
1802    COMMAND_PERIODIC_ONE_MPS_MEDIUM = 0x2126
1803    #: Periodic at one measurement per second, low repeatability.
1804    COMMAND_PERIODIC_ONE_MPS_LOW = 0x212D
1805    #: Periodic at two measurements per second, high repeatability.
1806    COMMAND_PERIODIC_TWO_MPS_HIGH = 0x2236
1807    #: Periodic at two measurements per second, medium repeatability.
1808    COMMAND_PERIODIC_TWO_MPS_MEDIUM = 0x2220
1809    #: Periodic at two measurements per second, low repeatability.
1810    COMMAND_PERIODIC_TWO_MPS_LOW = 0x222B
1811    #: Periodic at four measurements per second, high repeatability.
1812    COMMAND_PERIODIC_FOUR_MPS_HIGH = 0x2334
1813    #: Periodic at four measurements per second, medium repeatability.
1814    COMMAND_PERIODIC_FOUR_MPS_MEDIUM = 0x2322
1815    #: Periodic at four measurements per second, low repeatability.
1816    COMMAND_PERIODIC_FOUR_MPS_LOW = 0x2329
1817    #: Periodic at ten measurements per second, high repeatability.
1818    COMMAND_PERIODIC_TEN_MPS_HIGH = 0x2737
1819    #: Periodic at ten measurements per second, medium repeatability.
1820    COMMAND_PERIODIC_TEN_MPS_MEDIUM = 0x2721
1821    #: Periodic at ten measurements per second, low repeatability.
1822    COMMAND_PERIODIC_TEN_MPS_LOW = 0x272A
1823    #: Accelerated response time, four measurements per second.
1824    COMMAND_PERIODIC_ART = 0x2B32
1825    #: Fetch the latest periodic result.
1826    COMMAND_FETCH_DATA = 0xE000
1827    #: Leave periodic mode.
1828    COMMAND_BREAK = 0x3093
1829    #: Soft reset.
1830    COMMAND_SOFT_RESET = 0x30A2
1831    #: The general-call reset, addressed to 0x00.
1832    COMMAND_GENERAL_CALL_RESET = 0x0006
1833    #: Turn the on-die heater on.
1834    COMMAND_HEATER_ENABLE = 0x306D
1835    #: Turn the on-die heater off.
1836    COMMAND_HEATER_DISABLE = 0x3066
1837    #: Read the status register.
1838    COMMAND_READ_STATUS = 0xF32D
1839    #: Clear the status register.
1840    COMMAND_CLEAR_STATUS = 0x3041
1841
1842    def crc(self, data: bytes) -> int:
1843        """Compute the Sensirion CRC-8 the part appends to every word.
1844
1845        :param data: The bytes the checksum covers.
1846        :returns: The checksum.
1847        """
1848        return _sht3x_crc(bytes(data))
1849
1850    def word(self, frame: bytes) -> int:
1851        """Read a CRC-checked three-byte word frame.
1852
1853        :param frame: The two data bytes and their checksum.
1854        :returns: The 16-bit word.
1855        :raises ValueError: If the frame is not three bytes.
1856        :raises PamojaError: If the checksum does not match, which means the read
1857            was corrupted on the bus and should be repeated.
1858        """
1859        return _sht3x_word(bytes(frame))
1860
1861    def word_bytes(self, value: int) -> bytes:
1862        """Build the three bytes the part sends for a word: the word then its CRC.
1863
1864        :param value: The 16-bit word.
1865        :returns: The frame in transmission order.
1866        """
1867        return bytes(_sht3x_word_bytes(value))
1868
1869    def parse_measurement(self, frame: bytes) -> Sht3xMeasurement:
1870        """Parse and CRC-check a six-byte measurement frame.
1871
1872        :param frame: The temperature word, humidity word, and their checksums.
1873        :returns: The decoded reading, in raw words and physical units.
1874        :raises ValueError: If the frame is not six bytes.
1875        :raises PamojaError: If either checksum does not match.
1876        """
1877        return _sht3x_parse_measurement(bytes(frame))
1878
1879    def measurement_bytes(self, temperature_raw: int, humidity_raw: int) -> bytes:
1880        """Build the six bytes the part sends for a pair of raw words.
1881
1882        The inverse of :meth:`parse_measurement`, so a node can be written and tested
1883        against what a sensor sends without one attached.
1884
1885        :param temperature_raw: The raw temperature word.
1886        :param humidity_raw: The raw humidity word.
1887        :returns: The frame in transmission order, each word followed by its CRC.
1888        """
1889        return bytes(_sht3x_measurement_bytes(temperature_raw, humidity_raw))
1890
1891    def parse_status(self, frame: bytes) -> Sht3xStatus:
1892        """Parse and CRC-check a three-byte status frame.
1893
1894        :param frame: The status word and its checksum.
1895        :returns: The decoded status word and its flags.
1896        :raises ValueError: If the frame is not three bytes.
1897        :raises PamojaError: If the checksum does not match.
1898        """
1899        return _sht3x_parse_status(bytes(frame))
1900
1901    def status_from_bits(self, bits: int) -> Sht3xStatus:
1902        """Split a status word into its flags.
1903
1904        :param bits: The 16-bit status register.
1905        :returns: The decoded flags. Every value decodes, so this never raises.
1906        """
1907        return _sht3x_status_from_bits(bits)
1908
1909    def status_bytes(self, bits: int) -> bytes:
1910        """Build the three bytes the part sends for a status word, CRC last.
1911
1912        :param bits: The 16-bit status register.
1913        :returns: The frame in transmission order.
1914        """
1915        return bytes(_sht3x_status_bytes(bits))
1916
1917    def milli_celsius(self, raw: int) -> int:
1918        """Convert a raw temperature word to milli-degrees Celsius.
1919
1920        :param raw: The 16-bit temperature word.
1921        :returns: The temperature, exact in integer arithmetic.
1922        """
1923        return _sht3x_milli_celsius(raw)
1924
1925    def celsius(self, raw: int) -> float:
1926        """Convert a raw temperature word to degrees Celsius.
1927
1928        :param raw: The 16-bit temperature word.
1929        :returns: The temperature.
1930        """
1931        return _sht3x_celsius(raw)
1932
1933    def milli_fahrenheit(self, raw: int) -> int:
1934        """Convert a raw temperature word to milli-degrees Fahrenheit.
1935
1936        :param raw: The 16-bit temperature word.
1937        :returns: The temperature, from the datasheet's own Fahrenheit formula.
1938        """
1939        return _sht3x_milli_fahrenheit(raw)
1940
1941    def fahrenheit(self, raw: int) -> float:
1942        """Convert a raw temperature word to degrees Fahrenheit.
1943
1944        :param raw: The 16-bit temperature word.
1945        :returns: The temperature.
1946        """
1947        return _sht3x_fahrenheit(raw)
1948
1949    def milli_percent(self, raw: int) -> int:
1950        """Convert a raw humidity word to milli-percent.
1951
1952        :param raw: The 16-bit humidity word.
1953        :returns: The relative humidity, exact in integer arithmetic.
1954        """
1955        return _sht3x_milli_percent(raw)
1956
1957    def relative_humidity(self, raw: int) -> float:
1958        """Convert a raw humidity word to a relative humidity percentage.
1959
1960        :param raw: The 16-bit humidity word.
1961        :returns: The relative humidity.
1962        """
1963        return _sht3x_relative_humidity(raw)
1964
1965    def temperature_raw_from_milli_celsius(self, milli_celsius: int) -> int:
1966        """Build the temperature word that decodes to a temperature.
1967
1968        :param milli_celsius: The temperature in milli-degrees Celsius.
1969        :returns: The 16-bit word, clamped to the part's range.
1970        """
1971        return _sht3x_temperature_raw_from_milli_celsius(milli_celsius)
1972
1973    def temperature_raw_from_celsius(self, celsius: float) -> int:
1974        """Build the temperature word that decodes to a temperature in Celsius.
1975
1976        :param celsius: The temperature.
1977        :returns: The 16-bit word, clamped to the part's range.
1978        """
1979        return _sht3x_temperature_raw_from_celsius(celsius)
1980
1981    def temperature_raw_from_milli_fahrenheit(self, milli_fahrenheit: int) -> int:
1982        """Build the temperature word that decodes to a temperature in Fahrenheit.
1983
1984        :param milli_fahrenheit: The temperature in milli-degrees Fahrenheit.
1985        :returns: The 16-bit word, clamped to the part's range.
1986        """
1987        return _sht3x_temperature_raw_from_milli_fahrenheit(milli_fahrenheit)
1988
1989    def humidity_raw_from_milli_percent(self, milli_percent: int) -> int:
1990        """Build the humidity word that decodes to a relative humidity.
1991
1992        :param milli_percent: The relative humidity in milli-percent.
1993        :returns: The 16-bit word, clamped to full scale.
1994        """
1995        return _sht3x_humidity_raw_from_milli_percent(milli_percent)
1996
1997    def humidity_raw_from_relative_humidity(self, percent: float) -> int:
1998        """Build the humidity word that decodes to a relative humidity percentage.
1999
2000        :param percent: The relative humidity.
2001        :returns: The 16-bit word, clamped to full scale.
2002        """
2003        return _sht3x_humidity_raw_from_relative_humidity(percent)
2004
2005    def single_shot(self, repeatability: Sht3xRepeatability, clock_stretching: bool) -> int:
2006        """Return the single-shot command for a repeatability and clock mode.
2007
2008        :param repeatability: How hard the part works at the measurement.
2009        :param clock_stretching: Whether the part holds the clock until the result
2010            is ready, rather than making the driver poll for it.
2011        :returns: The 16-bit command word.
2012        :raises ValueError: If the repeatability is not one the part offers.
2013        """
2014        return _sht3x_single_shot(Sht3xRepeatability(repeatability).value, clock_stretching)
2015
2016    def periodic(self, repeatability: Sht3xRepeatability, rate: Sht3xRate) -> int:
2017        """Return the periodic-mode command for a repeatability and rate.
2018
2019        :param repeatability: How hard the part works at each measurement.
2020        :param rate: How often it measures.
2021        :returns: The 16-bit command word.
2022        :raises ValueError: If either setting is not one the part offers.
2023        """
2024        return _sht3x_periodic(
2025            Sht3xRepeatability(repeatability).value, Sht3xRate(rate).value
2026        )
2027
2028    def max_measurement_micros(self, repeatability: Sht3xRepeatability) -> int:
2029        """Return how long a measurement may take.
2030
2031        :param repeatability: The setting the measurement is taken at.
2032        :returns: The datasheet's worst case, in microseconds.
2033        :raises ValueError: If the repeatability is not one the part offers.
2034        """
2035        return _sht3x_max_measurement_micros(Sht3xRepeatability(repeatability).value)
2036
2037    def typical_measurement_micros(self, repeatability: Sht3xRepeatability) -> int:
2038        """Return how long a measurement typically takes.
2039
2040        :param repeatability: The setting the measurement is taken at.
2041        :returns: The datasheet's typical figure, in microseconds.
2042        :raises ValueError: If the repeatability is not one the part offers.
2043        """
2044        return _sht3x_typical_measurement_micros(Sht3xRepeatability(repeatability).value)
2045
2046    def interval_micros(self, rate: Sht3xRate) -> int:
2047        """Return the gap between periodic measurements.
2048
2049        :param rate: The periodic rate.
2050        :returns: The interval in microseconds.
2051        :raises ValueError: If the rate is not one the part offers.
2052        """
2053        return _sht3x_interval_micros(Sht3xRate(rate).value)
2054
2055class _Scd4xSim:
2056    """An SCD4x that is not there, for a bus with nothing plugged in.
2057
2058    It answers the serial number, data-ready, and measurement commands, each word with its
2059    checksum, and always has a result waiting.
2060    """
2061
2062    __slots__ = ()
2063
2064    #: The carbon dioxide :meth:`part` reports, in parts per million.
2065    CO2_PPM = 800
2066    #: The temperature :meth:`part` reports.
2067    CELSIUS = 22.5
2068    #: The relative humidity :meth:`part` reports, as a percentage.
2069    RELATIVE_HUMIDITY = 45.0
2070    #: The serial number every simulated part reports.
2071    SERIAL = 0x0000_5A4D_0C1E_2B3F
2072
2073    def part(self) -> CommandPart:
2074        """Make a part reading :attr:`CO2_PPM`, :attr:`CELSIUS`, and
2075        :attr:`RELATIVE_HUMIDITY`.
2076
2077        :returns: The part, to put on a simulated bus.
2078        """
2079        return CommandPart._wrap(_scd4x_sim_part())
2080
2081    def reporting(self, co2_ppm: int, celsius: float, relative_humidity: float) -> CommandPart:
2082        """Make a part that reads what it is asked to.
2083
2084        :param co2_ppm: The carbon dioxide it reports, in parts per million.
2085        :param celsius: The temperature it reports.
2086        :param relative_humidity: The humidity it reports, as a percentage.
2087        :returns: The part, to put on a simulated bus.
2088        """
2089        return CommandPart._wrap(_scd4x_sim_reporting(co2_ppm, celsius, relative_humidity))
2090
2091
2092class _Scd4x:
2093    """A Sensirion SCD40 or SCD41 carbon dioxide, temperature, and humidity sensor."""
2094
2095    __slots__ = ()
2096
2097    #: An SCD4x that is not there, for a bus with nothing plugged in.
2098    sim = _Scd4xSim()
2099
2100    #: The only address the part answers on.
2101    ADDRESS = 0x62
2102    #: The highest concentration the part reports, in parts per million.
2103    CO2_MAX_PPM = 40_000
2104    #: The temperature offset the part powers up with, in milli-degrees Celsius.
2105    DEFAULT_TEMPERATURE_OFFSET_MILLI_CELSIUS = 4_000
2106    #: How often periodic measurement produces a result, in milliseconds.
2107    PERIODIC_MEASUREMENT_INTERVAL_MS = 5_000
2108    #: How often low-power periodic measurement produces a result, in milliseconds.
2109    LOW_POWER_PERIODIC_MEASUREMENT_INTERVAL_MS = 30_000
2110    #: How long the part takes to become ready after power-up, in milliseconds.
2111    POWER_UP_TIME_MS = 1_000
2112    #: The word a forced recalibration returns when it did not take.
2113    FORCED_RECALIBRATION_FAILED = 0xFFFF
2114    #: Start periodic measurement.
2115    COMMAND_START_PERIODIC_MEASUREMENT = 0x21B1
2116    #: Read the latest result.
2117    COMMAND_READ_MEASUREMENT = 0xEC05
2118    #: Leave periodic measurement.
2119    COMMAND_STOP_PERIODIC_MEASUREMENT = 0x3F86
2120    #: Write the temperature offset.
2121    COMMAND_SET_TEMPERATURE_OFFSET = 0x241D
2122    #: Read the temperature offset.
2123    COMMAND_GET_TEMPERATURE_OFFSET = 0x2318
2124    #: Write the installation altitude.
2125    COMMAND_SET_SENSOR_ALTITUDE = 0x2427
2126    #: Read the installation altitude.
2127    COMMAND_GET_SENSOR_ALTITUDE = 0x2322
2128    #: Write the ambient pressure, which overrides the altitude.
2129    COMMAND_SET_AMBIENT_PRESSURE = 0xE000
2130    #: Run a forced recalibration against a known concentration.
2131    COMMAND_PERFORM_FORCED_RECALIBRATION = 0x362F
2132    #: Turn automatic self-calibration on or off.
2133    COMMAND_SET_AUTOMATIC_SELF_CALIBRATION_ENABLED = 0x2416
2134    #: Read whether automatic self-calibration is on.
2135    COMMAND_GET_AUTOMATIC_SELF_CALIBRATION_ENABLED = 0x2313
2136    #: Start low-power periodic measurement.
2137    COMMAND_START_LOW_POWER_PERIODIC_MEASUREMENT = 0x21AC
2138    #: Ask whether a result is waiting.
2139    COMMAND_GET_DATA_READY_STATUS = 0xE4B8
2140    #: Copy the settings to non-volatile memory.
2141    COMMAND_PERSIST_SETTINGS = 0x3615
2142    #: Read the serial number.
2143    COMMAND_GET_SERIAL_NUMBER = 0x3682
2144    #: Run the self test.
2145    COMMAND_PERFORM_SELF_TEST = 0x3639
2146    #: Restore the factory settings.
2147    COMMAND_PERFORM_FACTORY_RESET = 0x3632
2148    #: Reinitialize from the stored settings.
2149    COMMAND_REINIT = 0x3646
2150    #: Take one measurement and return to idle.
2151    COMMAND_MEASURE_SINGLE_SHOT = 0x219D
2152    #: Take one humidity and temperature measurement, without carbon dioxide.
2153    COMMAND_MEASURE_SINGLE_SHOT_RHT_ONLY = 0x2196
2154    #: Enter sleep, SCD41 only.
2155    COMMAND_POWER_DOWN = 0x36E0
2156    #: Leave sleep, SCD41 only.
2157    COMMAND_WAKE_UP = 0x36F6
2158
2159    def crc(self, data: bytes) -> int:
2160        """Compute the Sensirion CRC-8 the part appends to every word.
2161
2162        :param data: The bytes the checksum covers.
2163        :returns: The checksum.
2164        """
2165        return _scd4x_crc(bytes(data))
2166
2167    def word(self, frame: bytes) -> int:
2168        """Read a CRC-checked three-byte word frame.
2169
2170        :param frame: The two data bytes and their checksum.
2171        :returns: The 16-bit word.
2172        :raises ValueError: If the frame is not three bytes.
2173        :raises PamojaError: If the checksum does not match, which means the read
2174            was corrupted on the bus and should be repeated.
2175        """
2176        return _scd4x_word(bytes(frame))
2177
2178    def word_frame(self, value: int) -> bytes:
2179        """Build the three bytes the part sends for a word: the word then its CRC.
2180
2181        :param value: The 16-bit word.
2182        :returns: The frame in transmission order.
2183        """
2184        return bytes(_scd4x_word_frame(value))
2185
2186    def command_frame(self, command: int) -> bytes:
2187        """Build the two bytes that send a bare command.
2188
2189        :param command: The 16-bit command word.
2190        :returns: The bytes to write, most significant first.
2191        """
2192        return bytes(_scd4x_command_frame(command))
2193
2194    def write_frame(self, command: int, value: int) -> bytes:
2195        """Build the five bytes that send a command with an argument.
2196
2197        :param command: The 16-bit command word.
2198        :param value: The argument the command takes.
2199        :returns: The command, the argument, and the argument's CRC.
2200        """
2201        return bytes(_scd4x_write_frame(command, value))
2202
2203    def max_duration_ms(self, command: int) -> int | None:
2204        """Return how long a command may take.
2205
2206        :param command: The 16-bit command word.
2207        :returns: The datasheet's execution time in milliseconds, or ``None`` for a
2208            command that completes without one.
2209        """
2210        return _scd4x_max_duration_ms(command)
2211
2212    def allowed_during_measurement(self, command: int) -> bool:
2213        """Report whether the part accepts a command while it is measuring.
2214
2215        :param command: The 16-bit command word.
2216        :returns: Whether the command can be sent without stopping measurement first.
2217        """
2218        return _scd4x_allowed_during_measurement(command)
2219
2220    def parse_measurement(self, frame: bytes) -> Scd4xMeasurement:
2221        """Parse and CRC-check a nine-byte measurement frame.
2222
2223        :param frame: The three words and their checksums, as the device sent them.
2224        :returns: The decoded reading, in raw words and physical units.
2225        :raises ValueError: If the frame is not nine bytes.
2226        :raises PamojaError: If any checksum does not match.
2227        """
2228        return _scd4x_parse_measurement(bytes(frame))
2229
2230    def measurement_from_physical(
2231        self, co2_ppm: int, milli_celsius: int, humidity_milli_percent: int
2232    ) -> Scd4xMeasurement:
2233        """Build the measurement a sensor reporting these values would send.
2234
2235        :param co2_ppm: The carbon dioxide concentration in parts per million.
2236        :param milli_celsius: The temperature in milli-degrees Celsius.
2237        :param humidity_milli_percent: The relative humidity in milli-percent.
2238        :returns: The measurement, with the raw words the part would have reported.
2239        """
2240        return _scd4x_measurement_from_physical(
2241            co2_ppm, milli_celsius, humidity_milli_percent
2242        )
2243
2244    def measurement_bytes(
2245        self, co2_ppm: int, temperature_raw: int, humidity_raw: int
2246    ) -> bytes:
2247        """Build the nine bytes the part sends for a set of raw words.
2248
2249        The inverse of :meth:`parse_measurement`, so a node can be written and tested
2250        against what a sensor sends without one attached.
2251
2252        :param co2_ppm: The carbon dioxide concentration in parts per million.
2253        :param temperature_raw: The raw temperature word.
2254        :param humidity_raw: The raw humidity word.
2255        :returns: The frame in transmission order, each word followed by its CRC.
2256        """
2257        return bytes(_scd4x_measurement_bytes(co2_ppm, temperature_raw, humidity_raw))
2258
2259    def milli_celsius(self, raw: int) -> int:
2260        """Convert a raw temperature word to milli-degrees Celsius.
2261
2262        :param raw: The 16-bit temperature word.
2263        :returns: The temperature, exact in integer arithmetic.
2264        """
2265        return _scd4x_milli_celsius(raw)
2266
2267    def celsius(self, raw: int) -> float:
2268        """Convert a raw temperature word to degrees Celsius.
2269
2270        :param raw: The 16-bit temperature word.
2271        :returns: The temperature.
2272        """
2273        return _scd4x_celsius(raw)
2274
2275    def temperature_raw(self, milli_celsius: int) -> int:
2276        """Build the temperature word that decodes to a temperature.
2277
2278        :param milli_celsius: The temperature in milli-degrees Celsius.
2279        :returns: The 16-bit word, clamped to the part's range.
2280        """
2281        return _scd4x_temperature_raw(milli_celsius)
2282
2283    def humidity_milli_percent(self, raw: int) -> int:
2284        """Convert a raw humidity word to milli-percent.
2285
2286        :param raw: The 16-bit humidity word.
2287        :returns: The relative humidity, exact in integer arithmetic.
2288        """
2289        return _scd4x_humidity_milli_percent(raw)
2290
2291    def relative_humidity_percent(self, raw: int) -> float:
2292        """Convert a raw humidity word to a relative humidity percentage.
2293
2294        :param raw: The 16-bit humidity word.
2295        :returns: The relative humidity.
2296        """
2297        return _scd4x_relative_humidity_percent(raw)
2298
2299    def humidity_raw(self, milli_percent: int) -> int:
2300        """Build the humidity word that decodes to a relative humidity.
2301
2302        :param milli_percent: The relative humidity in milli-percent.
2303        :returns: The 16-bit word, clamped to full scale.
2304        """
2305        return _scd4x_humidity_raw(milli_percent)
2306
2307    def data_ready(self, word: int) -> bool:
2308        """Report whether a data-ready word says a measurement is waiting.
2309
2310        :param word: The word the data-ready command returned.
2311        :returns: Whether a result can be read.
2312        """
2313        return _scd4x_data_ready(word)
2314
2315    def temperature_offset_word(self, milli_celsius: int) -> int:
2316        """Build the word that programs a temperature offset.
2317
2318        The offset scales by 2^16, not by the 2^16 - 1 a measurement uses.
2319
2320        :param milli_celsius: The offset in milli-degrees Celsius.
2321        :returns: The word to write.
2322        """
2323        return _scd4x_temperature_offset_word(milli_celsius)
2324
2325    def temperature_offset_milli_celsius(self, word: int) -> int:
2326        """Convert a temperature-offset word back to milli-degrees Celsius.
2327
2328        :param word: The word the part returned.
2329        :returns: The offset in milli-degrees Celsius.
2330        """
2331        return _scd4x_temperature_offset_milli_celsius(word)
2332
2333    def ambient_pressure_word(self, pascals: int) -> int:
2334        """Build the word that programs an ambient pressure.
2335
2336        :param pascals: The ambient pressure.
2337        :returns: The word to write, in hundreds of pascals.
2338        """
2339        return _scd4x_ambient_pressure_word(pascals)
2340
2341    def ambient_pressure_pascals(self, word: int) -> int:
2342        """Convert an ambient-pressure word back to pascals.
2343
2344        :param word: The word the part holds.
2345        :returns: The ambient pressure.
2346        """
2347        return _scd4x_ambient_pressure_pascals(word)
2348
2349    def forced_recalibration_correction_ppm(self, word: int) -> int | None:
2350        """Read the correction the part reports after a forced recalibration.
2351
2352        :param word: The word the recalibration command returned.
2353        :returns: The correction in parts per million, or ``None`` if the
2354            recalibration did not take.
2355        """
2356        return _scd4x_forced_recalibration_correction_ppm(word)
2357
2358    def forced_recalibration_word(self, correction_ppm: int | None = None) -> int:
2359        """Build the word the part returns for a forced-recalibration outcome.
2360
2361        :param correction_ppm: The correction in parts per million, or ``None`` for
2362            a recalibration that did not take.
2363        :returns: The word.
2364        """
2365        return _scd4x_forced_recalibration_word(correction_ppm)
2366
2367    def automatic_self_calibration_enabled(self, word: int) -> bool:
2368        """Report whether a word says automatic self-calibration is on.
2369
2370        :param word: The word the part returned.
2371        :returns: Whether the part recalibrates itself against clean air.
2372        """
2373        return _scd4x_automatic_self_calibration_enabled(word)
2374
2375    def automatic_self_calibration_word(self, enabled: bool) -> int:
2376        """Build the word that turns automatic self-calibration on or off.
2377
2378        :param enabled: Whether to leave self-calibration running.
2379        :returns: The word to write.
2380        """
2381        return _scd4x_automatic_self_calibration_word(enabled)
2382
2383    def self_test_passed(self, word: int) -> bool:
2384        """Report whether a self-test word says the part passed.
2385
2386        :param word: The word the self-test command returned.
2387        :returns: Whether the part reported no malfunction.
2388        """
2389        return _scd4x_self_test_passed(word)
2390
2391    def serial_number(self, frame: bytes) -> int:
2392        """Read a CRC-checked nine-byte serial-number frame.
2393
2394        :param frame: The three words and their checksums.
2395        :returns: The 48-bit serial number.
2396        :raises ValueError: If the frame is not nine bytes.
2397        :raises PamojaError: If any checksum does not match.
2398        """
2399        return _scd4x_serial_number(bytes(frame))
2400
2401    def serial_number_frame(self, serial: int) -> bytes:
2402        """Build the nine bytes the part sends for a serial number.
2403
2404        :param serial: The 48-bit serial number.
2405        :returns: The frame in transmission order, each word followed by its CRC.
2406        """
2407        return bytes(_scd4x_serial_number_frame(serial))
2408
2409
2410class _Tmp117Sim:
2411    """A TMP117 that is not there, for a bus with nothing plugged in.
2412
2413    Its configuration register keeps the flags the part sets for itself whatever a driver
2414    writes, with the data-ready flag set, so every conversion reads as finished.
2415    """
2416
2417    __slots__ = ()
2418
2419    #: The temperature :meth:`part` reports.
2420    CELSIUS = 21.25
2421
2422    def part(self, address: int) -> WordPart:
2423        """Make a part reading :attr:`CELSIUS`.
2424
2425        :param address: The address it answers to.
2426        :returns: The part, to put on a simulated bus.
2427        """
2428        return WordPart._wrap(_tmp117_sim_part(address))
2429
2430    def reporting(self, address: int, celsius: float) -> WordPart:
2431        """Make a part that reads what it is asked to, to the nearest 7.8125 millidegrees.
2432
2433        :param address: The address it answers to.
2434        :param celsius: The temperature it reports.
2435        :returns: The part, to put on a simulated bus.
2436        """
2437        return WordPart._wrap(_tmp117_sim_reporting(address, celsius))
2438
2439
2440class _Tmp117:
2441    """A TI TMP117 precision thermometer."""
2442
2443    __slots__ = ()
2444
2445    #: The averaging codes.
2446    Averaging = Tmp117Averaging
2447    #: A TMP117 that is not there, for a bus with nothing plugged in.
2448    sim = _Tmp117Sim()
2449
2450    #: The value the device-ID register reads, which confirms the part.
2451    DEVICE_ID = 0x0117
2452    #: The value the configuration register reads after a reset.
2453    CONFIG_RESET = 0x0220
2454    #: The value the high-limit register holds after a reset.
2455    HIGH_LIMIT_RESET = 0x6000
2456    #: The value the low-limit register holds after a reset.
2457    LOW_LIMIT_RESET = 0x8000
2458    #: The value the result register holds before the first conversion.
2459    TEMP_RESULT_RESET = 0x8000
2460    #: The byte a general-call reset sends to address 0x00.
2461    GENERAL_CALL_RESET = 0x06
2462    #: The word written to the EEPROM-unlock register to allow a write.
2463    EEPROM_UNLOCK = 0x8000
2464    #: The address with ADD0 tied to GND.
2465    ADDRESS_ADD0_GND = 0x48
2466    #: The address with ADD0 tied to V+.
2467    ADDRESS_ADD0_VPLUS = 0x49
2468    #: The address with ADD0 tied to SDA.
2469    ADDRESS_ADD0_SDA = 0x4A
2470    #: The address with ADD0 tied to SCL.
2471    ADDRESS_ADD0_SCL = 0x4B
2472    #: The temperature result.
2473    REGISTER_TEMP_RESULT = 0x00
2474    #: The configuration register.
2475    REGISTER_CONFIGURATION = 0x01
2476    #: The high alert limit.
2477    REGISTER_THIGH_LIMIT = 0x02
2478    #: The low alert limit.
2479    REGISTER_TLOW_LIMIT = 0x03
2480    #: The EEPROM unlock register.
2481    REGISTER_EEPROM_UL = 0x04
2482    #: The first general-purpose EEPROM word.
2483    REGISTER_EEPROM1 = 0x05
2484    #: The second general-purpose EEPROM word.
2485    REGISTER_EEPROM2 = 0x06
2486    #: The temperature offset applied to every result.
2487    REGISTER_TEMP_OFFSET = 0x07
2488    #: The third general-purpose EEPROM word.
2489    REGISTER_EEPROM3 = 0x08
2490    #: The device-ID register.
2491    REGISTER_DEVICE_ID = 0x0F
2492
2493    def nano_celsius(self, raw: int) -> int:
2494        """Convert a raw temperature register to nano-degrees Celsius.
2495
2496        :param raw: The signed 16-bit register.
2497        :returns: The temperature, exact at the part's 7.8125 m°C resolution.
2498        """
2499        return _tmp117_nano_celsius(raw)
2500
2501    def micro_celsius(self, raw: int) -> int:
2502        """Convert a raw temperature register to micro-degrees Celsius.
2503
2504        :param raw: The signed 16-bit register.
2505        :returns: The temperature, truncated toward zero.
2506        """
2507        return _tmp117_micro_celsius(raw)
2508
2509    def celsius(self, raw: int) -> float:
2510        """Convert a raw temperature register to degrees Celsius.
2511
2512        :param raw: The signed 16-bit register.
2513        :returns: The temperature.
2514        """
2515        return _tmp117_celsius(raw)
2516
2517    def raw_from_micro_celsius(self, micro_celsius: int) -> int:
2518        """Build the temperature register that decodes to a temperature.
2519
2520        :param micro_celsius: The temperature in micro-degrees Celsius.
2521        :returns: The signed register, rounded to nearest and saturating at the
2522            part's range.
2523        """
2524        return _tmp117_raw_from_micro_celsius(micro_celsius)
2525
2526    def raw_from_celsius(self, celsius: float) -> int:
2527        """Build the temperature register that decodes to a temperature in Celsius.
2528
2529        :param celsius: The temperature.
2530        :returns: The signed register, saturating at the part's range.
2531        """
2532        return _tmp117_raw_from_celsius(celsius)
2533
2534    def temperature_bytes(self, raw: int) -> bytes:
2535        """Build the two bytes the part sends for a temperature register.
2536
2537        :param raw: The signed 16-bit register.
2538        :returns: The bytes, most significant first.
2539        """
2540        return bytes(_tmp117_temperature_bytes(raw))
2541
2542    def temperature_from_bytes(self, data: bytes) -> int:
2543        """Read the two bytes the part sends for a temperature register.
2544
2545        :param data: The two register bytes, most significant first.
2546        :returns: The signed register value.
2547        :raises ValueError: If the read is not two bytes.
2548        """
2549        return _tmp117_temperature_from_bytes(bytes(data))
2550
2551    def device_id(self, raw: int) -> int:
2552        """Read the device identifier out of a device-ID register.
2553
2554        :param raw: The device-ID register.
2555        :returns: The 12-bit identifier, :attr:`DEVICE_ID` for a TMP117.
2556        """
2557        return _tmp117_device_id(raw)
2558
2559    def revision(self, raw: int) -> int:
2560        """Read the die revision out of a device-ID register.
2561
2562        :param raw: The device-ID register.
2563        :returns: The 4-bit revision.
2564        """
2565        return _tmp117_revision(raw)
2566
2567    def high_alert(self, config: int) -> bool:
2568        """Report whether a configuration register flags a high alert.
2569
2570        :param config: The configuration register.
2571        :returns: Whether a result went above the high limit.
2572        """
2573        return _tmp117_high_alert(config)
2574
2575    def low_alert(self, config: int) -> bool:
2576        """Report whether a configuration register flags a low alert.
2577
2578        :param config: The configuration register.
2579        :returns: Whether a result went below the low limit.
2580        """
2581        return _tmp117_low_alert(config)
2582
2583    def data_ready(self, config: int) -> bool:
2584        """Report whether a configuration register says a result is ready.
2585
2586        :param config: The configuration register.
2587        :returns: Whether a conversion completed since the register was last read.
2588        """
2589        return _tmp117_data_ready(config)
2590
2591    def eeprom_busy(self, config: int) -> bool:
2592        """Report whether a configuration register says an EEPROM write is running.
2593
2594        :param config: The configuration register.
2595        :returns: Whether a programming cycle is still in progress.
2596        """
2597        return _tmp117_eeprom_busy(config)
2598
2599    def eeprom_unlock_busy(self, unlock: int) -> bool:
2600        """Report whether an EEPROM unlock register says a write is running.
2601
2602        :param unlock: The EEPROM unlock register.
2603        :returns: Whether a programming cycle is still in progress.
2604        """
2605        return _tmp117_eeprom_unlock_busy(unlock)
2606
2607    def config_bits(self, config: Tmp117Config) -> int:
2608        """Assemble the 16-bit configuration register value.
2609
2610        :param config: The settings to encode.
2611        :returns: The register value to write.
2612        """
2613        return _tmp117_config_bits(config)
2614
2615    def config_from_bits(self, bits: int) -> Tmp117Config:
2616        """Parse a 16-bit configuration register value.
2617
2618        :param bits: The register value, as read from the device.
2619        :returns: The decoded settings. Every value decodes, so this never raises.
2620        """
2621        return _tmp117_config_from_bits(bits)
2622
2623    def conversions(self, averaging: int) -> int:
2624        """Return how many conversions an averaging code folds into one result.
2625
2626        :param averaging: The averaging code, 0 to 3.
2627        :returns: The conversion count: 1, 8, 32, or 64.
2628        """
2629        return _tmp117_averaging_conversions(averaging)
2630
2631    def conversion_micros(self, averaging: int) -> int:
2632        """Return how long an averaging code takes to convert.
2633
2634        :param averaging: The averaging code, 0 to 3.
2635        :returns: The conversion time in microseconds.
2636        """
2637        return _tmp117_averaging_micros(averaging)
2638
2639    def nominal_micros(self, cycle: int) -> int:
2640        """Return the nominal cycle a conversion-cycle code selects.
2641
2642        :param cycle: The conversion-cycle code, 0 to 7.
2643        :returns: The nominal cycle in microseconds.
2644        """
2645        return _tmp117_cycle_nominal_micros(cycle)
2646
2647    def cycle_micros(self, cycle: int, averaging: int) -> int:
2648        """Return the result-update interval for a cycle and averaging code.
2649
2650        A cycle shorter than the conversion it asks for stretches to the conversion.
2651
2652        :param cycle: The conversion-cycle code, 0 to 7.
2653        :param averaging: The averaging code, 0 to 3.
2654        :returns: The interval in microseconds.
2655        """
2656        return _tmp117_cycle_micros(cycle, averaging)
2657
2658class _Hdc1080Sim:
2659    """An HDC1080 that is not there, for a bus with nothing plugged in."""
2660
2661    __slots__ = ()
2662
2663    #: The temperature :meth:`part` reports.
2664    CELSIUS = 22.5
2665    #: The relative humidity :meth:`part` reports, as a percentage.
2666    RELATIVE_HUMIDITY = 45.0
2667
2668    def part(self) -> WordPart:
2669        """Make a part reading :attr:`CELSIUS` and :attr:`RELATIVE_HUMIDITY`, at the one
2670        address an HDC1080 has.
2671
2672        :returns: The part, to put on a simulated bus.
2673        """
2674        return WordPart._wrap(_hdc1080_sim_part())
2675
2676    def reporting(self, celsius: float, relative_humidity: float) -> WordPart:
2677        """Make a part that reads what it is asked to, within three thousandths of a degree
2678        and two thousandths of a percent.
2679
2680        :param celsius: The temperature it reports.
2681        :param relative_humidity: The humidity it reports, as a percentage.
2682        :returns: The part, to put on a simulated bus.
2683        """
2684        return WordPart._wrap(_hdc1080_sim_reporting(celsius, relative_humidity))
2685
2686
2687class _Hdc1080:
2688    """A TI HDC1080 temperature and humidity sensor."""
2689
2690    __slots__ = ()
2691
2692    #: The temperature resolutions.
2693    TemperatureResolution = Hdc1080TemperatureResolution
2694    #: The humidity resolutions.
2695    HumidityResolution = Hdc1080HumidityResolution
2696    #: An HDC1080 that is not there, for a bus with nothing plugged in.
2697    sim = _Hdc1080Sim()
2698
2699    #: The only address the part answers on.
2700    ADDRESS = 0x40
2701    #: The value the manufacturer-ID register reads.
2702    MANUFACTURER_ID = 0x5449
2703    #: The value the device-ID register reads, which confirms the part.
2704    DEVICE_ID = 0x1050
2705    #: The value the configuration register reads after a reset.
2706    CONFIGURATION_RESET = 0x1000
2707    #: The temperature result.
2708    REGISTER_TEMPERATURE = 0x00
2709    #: The humidity result.
2710    REGISTER_HUMIDITY = 0x01
2711    #: The configuration register.
2712    REGISTER_CONFIGURATION = 0x02
2713    #: The top word of the serial number.
2714    REGISTER_SERIAL_ID_HIGH = 0xFB
2715    #: The middle word of the serial number.
2716    REGISTER_SERIAL_ID_MID = 0xFC
2717    #: The bottom word of the serial number.
2718    REGISTER_SERIAL_ID_LOW = 0xFD
2719    #: The manufacturer-ID register.
2720    REGISTER_MANUFACTURER_ID = 0xFE
2721    #: The device-ID register.
2722    REGISTER_DEVICE_ID = 0xFF
2723
2724    def milli_celsius(self, raw: int) -> int:
2725        """Convert a raw temperature register to milli-degrees Celsius.
2726
2727        :param raw: The 16-bit register.
2728        :returns: The temperature, exact in integer arithmetic.
2729        """
2730        return _hdc1080_milli_celsius(raw)
2731
2732    def celsius(self, raw: int) -> float:
2733        """Convert a raw temperature register to degrees Celsius.
2734
2735        :param raw: The 16-bit register.
2736        :returns: The temperature.
2737        """
2738        return _hdc1080_celsius(raw)
2739
2740    def milli_percent(self, raw: int) -> int:
2741        """Convert a raw humidity register to milli-percent.
2742
2743        :param raw: The 16-bit register.
2744        :returns: The relative humidity, exact in integer arithmetic.
2745        """
2746        return _hdc1080_milli_percent(raw)
2747
2748    def relative_humidity(self, raw: int) -> float:
2749        """Convert a raw humidity register to a relative humidity percentage.
2750
2751        :param raw: The 16-bit register.
2752        :returns: The relative humidity.
2753        """
2754        return _hdc1080_relative_humidity(raw)
2755
2756    def temperature_register(self, milli_celsius: int) -> int:
2757        """Build the temperature register that decodes to a temperature.
2758
2759        :param milli_celsius: The temperature in milli-degrees Celsius.
2760        :returns: The 14-bit code in bits 15:2, clamped to the part's range.
2761        """
2762        return _hdc1080_temperature_register(milli_celsius)
2763
2764    def humidity_register(self, milli_percent: int) -> int:
2765        """Build the humidity register that decodes to a relative humidity.
2766
2767        :param milli_percent: The relative humidity in milli-percent.
2768        :returns: The 14-bit code in bits 15:2, clamped to full scale.
2769        """
2770        return _hdc1080_humidity_register(milli_percent)
2771
2772    def serial_id(self, high: int, mid: int, low: int) -> int:
2773        """Join the three serial-ID registers into the serial number.
2774
2775        :param high: The top serial-ID register.
2776        :param mid: The middle serial-ID register.
2777        :param low: The bottom serial-ID register.
2778        :returns: The 40-bit serial number.
2779        """
2780        return _hdc1080_serial_id(high, mid, low)
2781
2782    def serial_id_registers(self, serial: int) -> tuple[int, int, int]:
2783        """Split a serial number back into the three serial-ID registers.
2784
2785        :param serial: The 40-bit serial number.
2786        :returns: The high, middle, and low registers.
2787        """
2788        high, mid, low = _hdc1080_serial_id_registers(serial)
2789        return high, mid, low
2790
2791    def parse_measurement(self, data: bytes) -> Hdc1080Measurement:
2792        """Parse the four bytes a sequential read returns.
2793
2794        The part appends no checksum, so every read decodes.
2795
2796        :param data: The temperature and humidity registers, most significant first.
2797        :returns: The decoded reading, in raw registers and physical units.
2798        :raises ValueError: If the read is not four bytes.
2799        """
2800        return _hdc1080_parse_measurement(bytes(data))
2801
2802    def measurement_from_physical(
2803        self, milli_celsius: int, milli_percent: int
2804    ) -> Hdc1080Measurement:
2805        """Build the measurement a sensor reporting these values would send.
2806
2807        :param milli_celsius: The temperature in milli-degrees Celsius.
2808        :param milli_percent: The relative humidity in milli-percent.
2809        :returns: The measurement, with the raw registers the part would have held.
2810        """
2811        return _hdc1080_measurement_from_physical(milli_celsius, milli_percent)
2812
2813    def measurement_bytes(self, temperature_raw: int, humidity_raw: int) -> bytes:
2814        """Build the four bytes the part sends for a pair of raw registers.
2815
2816        The inverse of :meth:`parse_measurement`, so a node can be written and tested
2817        against what a sensor sends without one attached.
2818
2819        :param temperature_raw: The raw temperature register.
2820        :param humidity_raw: The raw humidity register.
2821        :returns: The four bytes in read order.
2822        """
2823        return bytes(_hdc1080_measurement_bytes(temperature_raw, humidity_raw))
2824
2825    def config_from_register(self, raw: int) -> Hdc1080Config:
2826        """Parse a configuration register value.
2827
2828        :param raw: The register value, as read from the device.
2829        :returns: The decoded settings.
2830        :raises PamojaError: If the humidity-resolution field holds the code the
2831            datasheet leaves undefined, which no working part reports.
2832        """
2833        return _hdc1080_config_from_register(raw)
2834
2835    def config_to_register(self, config: Hdc1080Config) -> int:
2836        """Assemble a configuration register value.
2837
2838        :param config: The settings to encode.
2839        :returns: The register value to write.
2840        :raises ValueError: If either resolution is not one the part offers.
2841        """
2842        return _hdc1080_config_to_register(config)
2843
2844    def conversion_time_micros(self, config: Hdc1080Config) -> int:
2845        """Return how long to wait after triggering the part in this configuration.
2846
2847        :param config: The settings the part is running.
2848        :returns: The conversion time in microseconds, both channels in sequential
2849            mode.
2850        :raises ValueError: If either resolution is not one the part offers.
2851        """
2852        return _hdc1080_conversion_time_micros(config)
2853
2854    def temperature_conversion_micros(self, bits: int) -> int:
2855        """Return how long a temperature conversion takes.
2856
2857        :param bits: The temperature resolution in bits: 14 or 11.
2858        :returns: The conversion time in microseconds.
2859        :raises ValueError: If the resolution is not one the part offers.
2860        """
2861        return _hdc1080_temperature_conversion_micros(bits)
2862
2863    def humidity_conversion_micros(self, bits: int) -> int:
2864        """Return how long a humidity conversion takes.
2865
2866        :param bits: The humidity resolution in bits: 14, 11, or 8.
2867        :returns: The conversion time in microseconds.
2868        :raises ValueError: If the resolution is not one the part offers.
2869        """
2870        return _hdc1080_humidity_conversion_micros(bits)
2871
2872
2873class _Opt3001Sim:
2874    """An OPT3001 that is not there, for a bus with nothing plugged in.
2875
2876    Its configuration register keeps the flags the part sets for itself whatever a driver
2877    writes, with the conversion-ready flag set, so every conversion reads as finished.
2878    """
2879
2880    __slots__ = ()
2881
2882    #: The illuminance :meth:`part` reports.
2883    LUX = 380.0
2884
2885    def part(self, address: int) -> WordPart:
2886        """Make a part reading :attr:`LUX`.
2887
2888        :param address: The address it answers to.
2889        :returns: The part, to put on a simulated bus.
2890        """
2891        return WordPart._wrap(_opt3001_sim_part(address))
2892
2893    def reporting(self, address: int, lux: float) -> WordPart:
2894        """Make a part that reads what it is asked to, to the nearest step its exponent and
2895        mantissa represent.
2896
2897        :param address: The address it answers to.
2898        :param lux: The illuminance it reports.
2899        :returns: The part, to put on a simulated bus.
2900        """
2901        return WordPart._wrap(_opt3001_sim_reporting(address, lux))
2902
2903
2904class _Opt3001:
2905    """A TI OPT3001 ambient light sensor."""
2906
2907    __slots__ = ()
2908
2909    #: The conversion times.
2910    ConversionTime = Opt3001ConversionTime
2911    #: An OPT3001 that is not there, for a bus with nothing plugged in.
2912    sim = _Opt3001Sim()
2913
2914    #: The address the part answers on with ADDR tied to GND.
2915    ADDRESS_GND = 0x44
2916    #: The address it answers on with ADDR tied to VDD.
2917    ADDRESS_VDD = 0x45
2918    #: The address it answers on with ADDR tied to SDA.
2919    ADDRESS_SDA = 0x46
2920    #: The address it answers on with ADDR tied to SCL.
2921    ADDRESS_SCL = 0x47
2922    #: The value the manufacturer-ID register reads.
2923    MANUFACTURER_ID = 0x5449
2924    #: The value the device-ID register reads, which confirms the part.
2925    DEVICE_ID = 0x3001
2926    #: The value the configuration register reads after a reset.
2927    CONFIGURATION_RESET = 0xC810
2928    #: The value the low-limit register holds after a reset.
2929    LOW_LIMIT_RESET = 0x0000
2930    #: The value the high-limit register holds after a reset.
2931    HIGH_LIMIT_RESET = 0xBFFF
2932    #: The low-limit value that turns the INT pin into an end-of-conversion signal.
2933    LOW_LIMIT_END_OF_CONVERSION = 0xC000
2934    #: The range number that lets the part choose its own full scale.
2935    RANGE_AUTOMATIC = 0b1100
2936    #: The highest fixed range number.
2937    RANGE_MAX = 11
2938    #: The result register.
2939    REGISTER_RESULT = 0x00
2940    #: The configuration register.
2941    REGISTER_CONFIGURATION = 0x01
2942    #: The low limit.
2943    REGISTER_LOW_LIMIT = 0x02
2944    #: The high limit.
2945    REGISTER_HIGH_LIMIT = 0x03
2946    #: The manufacturer-ID register.
2947    REGISTER_MANUFACTURER_ID = 0x7E
2948    #: The device-ID register.
2949    REGISTER_DEVICE_ID = 0x7F
2950
2951    def lsb_milli_lux(self, exponent: int) -> int | None:
2952        """Return the illuminance one count carries at an exponent.
2953
2954        :param exponent: The result's exponent field, 0 to 11.
2955        :returns: The step in milli-lux, or ``None`` for a reserved exponent.
2956        """
2957        return _opt3001_lsb_milli_lux(exponent)
2958
2959    def full_scale_milli_lux(self, range_number: int) -> int | None:
2960        """Return the full scale a range number covers.
2961
2962        :param range_number: The range number, 0 to 11.
2963        :returns: The full scale in milli-lux, or ``None`` for a reserved range,
2964            which includes the automatic-range code.
2965        """
2966        return _opt3001_full_scale_milli_lux(range_number)
2967
2968    def milli_lux(self, raw: int) -> int:
2969        """Convert a raw result register to milli-lux.
2970
2971        :param raw: The register value, an exponent and a 12-bit mantissa.
2972        :returns: The illuminance, exact in integer arithmetic.
2973        """
2974        return _opt3001_milli_lux(raw)
2975
2976    def lux(self, raw: int) -> float:
2977        """Convert a raw result register to lux.
2978
2979        :param raw: The register value.
2980        :returns: The illuminance.
2981        """
2982        return _opt3001_lux(raw)
2983
2984    def raw_from_milli_lux(self, milli_lux: int) -> int:
2985        """Build the result register that decodes to an illuminance.
2986
2987        The smallest exponent that holds the value is used, so the mantissa keeps
2988        as much resolution as the format allows.
2989
2990        :param milli_lux: The illuminance in milli-lux.
2991        :returns: The register value, saturating at full scale.
2992        """
2993        return _opt3001_raw_from_milli_lux(milli_lux)
2994
2995    def word_from_bytes(self, data: bytes) -> int:
2996        """Read the two bytes the part sends for a register.
2997
2998        :param data: The register bytes, most significant first.
2999        :returns: The register value.
3000        :raises ValueError: If the read is not two bytes.
3001        """
3002        return _opt3001_word_from_bytes(bytes(data))
3003
3004    def word_to_bytes(self, word: int) -> bytes:
3005        """Build the two bytes the part sends for a register.
3006
3007        :param word: The register value.
3008        :returns: The bytes, most significant first.
3009        """
3010        return bytes(_opt3001_word_to_bytes(word))
3011
3012    def config_bits(self, config: Opt3001Config) -> int:
3013        """Assemble the 16-bit configuration register value.
3014
3015        The read-only status bits are written as zero.
3016
3017        :param config: The settings to encode.
3018        :returns: The register value to write.
3019        """
3020        return _opt3001_config_bits(config)
3021
3022    def config_from_bits(self, bits: int) -> Opt3001Config:
3023        """Parse a 16-bit configuration register value.
3024
3025        :param bits: The register value, as read from the device.
3026        :returns: The decoded settings. Every value decodes, so this never raises.
3027        """
3028        return _opt3001_config_from_bits(bits)
3029
3030    def conversion_millis(self, long_conversion: bool) -> int:
3031        """Return the conversion time a setting selects.
3032
3033        :param long_conversion: Whether the 800 ms conversion is selected rather
3034            than the 100 ms one.
3035        :returns: The conversion time in milliseconds.
3036        """
3037        return _opt3001_conversion_millis(long_conversion)
3038
3039    def fault_count(self, code: int) -> int:
3040        """Return how many consecutive faults a fault-count code requires.
3041
3042        :param code: The fault-count code, 0 to 3.
3043        :returns: The fault count: 1, 2, 4, or 8.
3044        """
3045        return _opt3001_fault_count(code)
3046
3047    def is_automatic_range(self, range_number: int) -> bool:
3048        """Report whether a range number sets the full scale automatically.
3049
3050        :param range_number: The range number from a configuration register.
3051        :returns: Whether the part chooses its own full scale.
3052        """
3053        return _opt3001_is_automatic_range(range_number)
3054
3055
3056class _Ina226Sim:
3057    """An INA226 that is not there, for a bus with nothing plugged in.
3058
3059    It carries TI's manufacturer id and the INA226 die id, its conversion-ready flag is set,
3060    and :meth:`reporting` takes the same shunt and largest current a driver is given.
3061    """
3062
3063    __slots__ = ()
3064
3065    #: The shunt :meth:`part` sits across, in milliohms.
3066    SHUNT_MILLIOHMS = 100
3067    #: The largest current :meth:`part` is sized for, in microamps.
3068    MAX_MICROAMPS = 3_200_000
3069    #: The bus voltage :meth:`part` reports, in microvolts.
3070    BUS_MICROVOLTS = 12_000_000
3071    #: The current :meth:`part` reports, in microamps.
3072    MICROAMPS = 500_000
3073
3074    def part(self, address: int) -> WordPart:
3075        """Make a part carrying 500 mA at 12 V through the shunt a driver starts with.
3076
3077        :param address: The address it answers to.
3078        :returns: The part, to put on a simulated bus.
3079        """
3080        return WordPart._wrap(_ina226_sim_part(address))
3081
3082    def reporting(
3083        self,
3084        address: int,
3085        shunt_milliohms: int,
3086        max_microamps: int,
3087        bus_microvolts: int,
3088        microamps: int,
3089    ) -> WordPart:
3090        """Make a part that reads what it is asked to, on the steps its registers count
3091        in: 1.25 mV of bus, 2.5 uV of shunt, and the calibration's current step.
3092
3093        :param address: The address it answers to.
3094        :param shunt_milliohms: The shunt, as the driver is given it.
3095        :param max_microamps: The largest current, as the driver is given it.
3096        :param bus_microvolts: The bus voltage it reports.
3097        :param microamps: The current it reports; negative flows the other way.
3098        :returns: The part, to put on a simulated bus.
3099        """
3100        return WordPart._wrap(
3101            _ina226_sim_reporting(
3102                address, shunt_milliohms, max_microamps, bus_microvolts, microamps
3103            )
3104        )
3105
3106
3107class _Ina226:
3108    """A TI INA226 current, voltage, and power monitor."""
3109
3110    __slots__ = ()
3111
3112    #: An INA226 that is not there, for a bus with nothing plugged in.
3113    sim = _Ina226Sim()
3114
3115    #: The address with both A1 and A0 tied to GND.
3116    BASE_ADDRESS = 0x40
3117    #: The value the manufacturer-ID register reads.
3118    MANUFACTURER_ID = 0x5449
3119    #: The device identifier the die-ID register carries for an INA226.
3120    DEVICE_ID = 0x226
3121    #: The value the configuration register reads after a reset.
3122    CONFIG_RESET = 0x4127
3123    #: The shunt voltage one count carries, in nanovolts.
3124    SHUNT_LSB_NANOVOLTS = 2_500
3125    #: The bus voltage one count carries, in microvolts.
3126    BUS_LSB_MICROVOLTS = 1_250
3127    #: How many times the power LSB is the current LSB.
3128    POWER_LSB_RATIO = 25
3129    #: An address pin tied to GND.
3130    PIN_GROUND = 0
3131    #: An address pin tied to VS.
3132    PIN_SUPPLY = 1
3133    #: An address pin tied to SDA.
3134    PIN_SDA = 2
3135    #: An address pin tied to SCL.
3136    PIN_SCL = 3
3137    #: The configuration register.
3138    REGISTER_CONFIGURATION = 0x00
3139    #: The shunt voltage result.
3140    REGISTER_SHUNT_VOLTAGE = 0x01
3141    #: The bus voltage result.
3142    REGISTER_BUS_VOLTAGE = 0x02
3143    #: The power result.
3144    REGISTER_POWER = 0x03
3145    #: The current result.
3146    REGISTER_CURRENT = 0x04
3147    #: The calibration register.
3148    REGISTER_CALIBRATION = 0x05
3149    #: The Mask/Enable register.
3150    REGISTER_MASK_ENABLE = 0x06
3151    #: The alert limit.
3152    REGISTER_ALERT_LIMIT = 0x07
3153    #: The manufacturer-ID register.
3154    REGISTER_MANUFACTURER_ID = 0xFE
3155    #: The die-ID register.
3156    REGISTER_DIE_ID = 0xFF
3157
3158    def address(self, a1: int, a0: int) -> int:
3159        """Return the 7-bit address the A1 and A0 pins select.
3160
3161        :param a1: What the A1 pin is tied to, one of the ``PIN_`` codes.
3162        :param a0: What the A0 pin is tied to.
3163        :returns: The address, 0x40 to 0x4F.
3164        :raises ValueError: If either pin code is not 0, 1, 2, or 3.
3165        """
3166        return _ina226_address(a1, a0)
3167
3168    def averaging_samples(self, averaging: int) -> int:
3169        """Return how many samples an averaging code folds into one result.
3170
3171        :param averaging: The averaging code, 0 to 7.
3172        :returns: The sample count, from 1 to 1024.
3173        """
3174        return _ina226_averaging_samples(averaging)
3175
3176    def conversion_micros(self, conversion_time: int) -> int:
3177        """Return the conversion time a code selects.
3178
3179        :param conversion_time: The conversion-time code, 0 to 7.
3180        :returns: The typical conversion time in microseconds.
3181        """
3182        return _ina226_conversion_micros(conversion_time)
3183
3184    def measures_shunt(self, mode: int) -> bool:
3185        """Report whether a mode code converts the shunt voltage.
3186
3187        :param mode: The operating-mode code, 0 to 7.
3188        :returns: Whether the shunt input is converted.
3189        """
3190        return _ina226_measures_shunt(mode)
3191
3192    def measures_bus(self, mode: int) -> bool:
3193        """Report whether a mode code converts the bus voltage.
3194
3195        :param mode: The operating-mode code, 0 to 7.
3196        :returns: Whether the bus input is converted.
3197        """
3198        return _ina226_measures_bus(mode)
3199
3200    def is_continuous(self, mode: int) -> bool:
3201        """Report whether a mode code keeps converting after the first result.
3202
3203        :param mode: The operating-mode code, 0 to 7.
3204        :returns: Whether conversions run back to back.
3205        """
3206        return _ina226_is_continuous(mode)
3207
3208    def config_from_register(self, raw: int) -> Ina226Config:
3209        """Parse a configuration register value.
3210
3211        :param raw: The register value, as read from the device.
3212        :returns: The decoded settings. Every value decodes, so this never raises.
3213        """
3214        return _ina226_config_from_register(raw)
3215
3216    def config_to_register(self, config: Ina226Config) -> int:
3217        """Assemble a configuration register value.
3218
3219        :param config: The settings to encode.
3220        :returns: The register value to write, with reserved bit 14 set as at reset.
3221        """
3222        return _ina226_config_to_register(config)
3223
3224    def update_micros(self, config: Ina226Config) -> int:
3225        """Return how often the part in this configuration updates its results.
3226
3227        :param config: The settings the part is running.
3228        :returns: The update interval in microseconds, or 0 in power-down.
3229        """
3230        return _ina226_update_micros(config)
3231
3232    def mask_enable_from_register(self, raw: int) -> Ina226MaskEnable:
3233        """Parse a Mask/Enable register value.
3234
3235        :param raw: The register value, as read from the device.
3236        :returns: The decoded enables and flags.
3237        """
3238        return _ina226_mask_enable_from_register(raw)
3239
3240    def mask_enable_to_register(self, mask: Ina226MaskEnable) -> int:
3241        """Assemble a Mask/Enable register value.
3242
3243        :param mask: The enables and flags to encode.
3244        :returns: The register value to write.
3245        """
3246        return _ina226_mask_enable_to_register(mask)
3247
3248    def active_alert_function(
3249        self, mask: Ina226MaskEnable
3250    ) -> Ina226AlertFunction | None:
3251        """Return the alert function the pin actually responds to.
3252
3253        Only one limit function drives the pin at a time; when several are enabled
3254        the part honors the most significant bit.
3255
3256        :param mask: The enables and flags the part is running.
3257        :returns: The function the pin follows, or ``None`` if no limit function is
3258            enabled.
3259        """
3260        function = _ina226_active_alert_function(mask)
3261        return None if function is None else Ina226AlertFunction(function)
3262
3263    def die_id(self, raw: int) -> Ina226DieId:
3264        """Split a die-ID register into its device and revision fields.
3265
3266        :param raw: The die-ID register.
3267        :returns: The device identifier and die revision.
3268        """
3269        return _ina226_die_id(raw)
3270
3271    def identify(self, manufacturer_id: int, die_id: int) -> Ina226DieId:
3272        """Check that a pair of identification registers belongs to an INA226.
3273
3274        :param manufacturer_id: The manufacturer-ID register.
3275        :param die_id: The die-ID register.
3276        :returns: The device identifier and die revision.
3277        :raises PamojaError: If either register does not carry the value the
3278            datasheet fixes, which means a different part answered at that address
3279            and its readings must not be trusted.
3280        """
3281        return _ina226_identify(manufacturer_id, die_id)
3282
3283    def calibration(self, current_lsb_microamps: int, shunt_milliohms: int) -> int:
3284        """Compute the calibration register for a shunt and current resolution.
3285
3286        :param current_lsb_microamps: The microamps per count the current register
3287            should carry.
3288        :param shunt_milliohms: The shunt resistor value.
3289        :returns: The register value to write.
3290        """
3291        return _ina226_calibration(current_lsb_microamps, shunt_milliohms)
3292
3293    def minimum_current_lsb_microamps(self, max_expected_microamps: int) -> int:
3294        """Return the smallest current resolution that still covers a maximum.
3295
3296        :param max_expected_microamps: The largest current the application measures.
3297        :returns: The minimum current LSB in microamps.
3298        """
3299        return _ina226_minimum_current_lsb_microamps(max_expected_microamps)
3300
3301    def shunt_nanovolts(self, raw: int) -> int:
3302        """Convert a raw shunt-voltage register to nanovolts.
3303
3304        :param raw: The signed register value.
3305        :returns: The shunt voltage, at 2.5 uV per count.
3306        """
3307        return _ina226_shunt_nanovolts(raw)
3308
3309    def shunt_millivolts(self, raw: int) -> float:
3310        """Convert a raw shunt-voltage register to millivolts.
3311
3312        :param raw: The signed register value.
3313        :returns: The shunt voltage.
3314        """
3315        return _ina226_shunt_millivolts(raw)
3316
3317    def bus_microvolts(self, raw: int) -> int:
3318        """Convert a raw bus-voltage register to microvolts.
3319
3320        :param raw: The register value.
3321        :returns: The bus voltage, at 1.25 mV per count.
3322        """
3323        return _ina226_bus_microvolts(raw)
3324
3325    def bus_volts(self, raw: int) -> float:
3326        """Convert a raw bus-voltage register to volts.
3327
3328        :param raw: The register value.
3329        :returns: The bus voltage.
3330        """
3331        return _ina226_bus_volts(raw)
3332
3333    def current_microamps(self, raw: int, current_lsb_microamps: int) -> int:
3334        """Convert a raw current register to microamps.
3335
3336        :param raw: The signed register value.
3337        :param current_lsb_microamps: The resolution the calibration selected.
3338        :returns: The current.
3339        """
3340        return _ina226_current_microamps(raw, current_lsb_microamps)
3341
3342    def current_amps(self, raw: int, current_lsb_microamps: int) -> float:
3343        """Convert a raw current register to amps.
3344
3345        :param raw: The signed register value.
3346        :param current_lsb_microamps: The resolution the calibration selected.
3347        :returns: The current.
3348        """
3349        return _ina226_current_amps(raw, current_lsb_microamps)
3350
3351    def power_microwatts(self, raw: int, current_lsb_microamps: int) -> int:
3352        """Convert a raw power register to microwatts.
3353
3354        :param raw: The register value.
3355        :param current_lsb_microamps: The resolution the calibration selected.
3356        :returns: The power. The power LSB is fixed at 25 times the current LSB.
3357        """
3358        return _ina226_power_microwatts(raw, current_lsb_microamps)
3359
3360    def power_watts(self, raw: int, current_lsb_microamps: int) -> float:
3361        """Convert a raw power register to watts.
3362
3363        :param raw: The register value.
3364        :param current_lsb_microamps: The resolution the calibration selected.
3365        :returns: The power.
3366        """
3367        return _ina226_power_watts(raw, current_lsb_microamps)
3368
3369    def shunt_register(self, nanovolts: int) -> int:
3370        """Build the shunt-voltage register a monitor reports for a shunt voltage.
3371
3372        The inverse of :meth:`shunt_nanovolts`, so a node can be written and tested
3373        against what a monitor sends without one attached.
3374
3375        :param nanovolts: The shunt voltage in nanovolts.
3376        :returns: The signed register value.
3377        """
3378        return _ina226_shunt_register(nanovolts)
3379
3380    def bus_register(self, microvolts: int) -> int:
3381        """Build the bus-voltage register a monitor reports for a bus voltage.
3382
3383        :param microvolts: The bus voltage in microvolts.
3384        :returns: The register value.
3385        """
3386        return _ina226_bus_register(microvolts)
3387
3388    def current_register(self, microamps: int, current_lsb_microamps: int) -> int:
3389        """Build the current register a monitor reports for a current.
3390
3391        :param microamps: The current in microamps.
3392        :param current_lsb_microamps: The current LSB the calibration was set for.
3393        :returns: The signed register value.
3394        """
3395        return _ina226_current_register(microamps, current_lsb_microamps)
3396
3397    def power_register(self, microwatts: int, current_lsb_microamps: int) -> int:
3398        """Build the power register a monitor reports for a power.
3399
3400        :param microwatts: The power in microwatts.
3401        :param current_lsb_microamps: The current LSB the calibration was set for.
3402        :returns: The register value.
3403        """
3404        return _ina226_power_register(microwatts, current_lsb_microamps)
3405
3406    def current_register_from_shunt(self, shunt: int, calibration: int) -> int:
3407        """Compute the current register the chip derives from a shunt reading.
3408
3409        :param shunt: The signed shunt-voltage register.
3410        :param calibration: The calibration register the part is running.
3411        :returns: The signed current register.
3412        """
3413        return _ina226_current_register_from_shunt(shunt, calibration)
3414
3415    def power_register_from_current(self, current: int, bus: int) -> int:
3416        """Compute the power register the chip derives from a current reading.
3417
3418        :param current: The signed current register.
3419        :param bus: The bus-voltage register.
3420        :returns: The power register.
3421        """
3422        return _ina226_power_register_from_current(current, bus)
3423
3424
3425class Bmp280:
3426    """A Bosch BMP280 driven over an :class:`~pamoja.hal.I2cBus`, measuring on demand in
3427    forced mode.
3428
3429    Nothing is sent until :meth:`init` or the first :meth:`measure`. The driver holds its
3430    own share of the bus, and releases the interpreter while the part answers.
3431
3432    >>> from pamoja.hal import I2cBus
3433    >>> bus = I2cBus.simulated([bmp280.sim.part(bmp280.ADDRESS_PRIMARY)])
3434    >>> f"{Bmp280(bus, bmp280.ADDRESS_PRIMARY).measure().celsius:.2f}"
3435    '20.44'
3436    """
3437
3438    __slots__ = ("_native",)
3439
3440    def __init__(
3441        self,
3442        bus: I2cBus,
3443        address: int,
3444        *,
3445        temperature: Bmp280Oversampling = Bmp280Oversampling.X1,
3446        pressure: Bmp280Oversampling = Bmp280Oversampling.X1,
3447        filter: int = 0,
3448    ) -> None:
3449        """Make a driver for the part at ``address`` on ``bus``.
3450
3451        :param bus: The bus the part is on.
3452        :param address: ``bmp280.ADDRESS_PRIMARY`` with SDO low, or
3453            ``bmp280.ADDRESS_SECONDARY`` with SDO high.
3454        :param temperature: The temperature oversampling.
3455        :param pressure: The pressure oversampling.
3456        :param filter: The IIR filter's three-bit code, ``0`` for the filter off, written
3457            as given.
3458        """
3459        self._native = _NativeBmp280(
3460            bus._native, address, int(temperature), int(pressure), int(filter)
3461        )
3462
3463    def init(self) -> None:
3464        """Reset the part, check it is a BMP280, read its trimming, and write the settings,
3465        leaving the part asleep.
3466
3467        :raises PamojaError: If nothing answers at the address, another part does, or the
3468            trimming never finishes loading.
3469        """
3470        self._native.init()
3471
3472    def measure(self) -> Bmp280Reading:
3473        """Run one forced measurement and compensate it, initializing the part first if
3474        :meth:`init` has not run.
3475
3476        :returns: The reading.
3477        :raises PamojaError: As :meth:`init`, and when the part is still measuring after
3478            the datasheet's time.
3479        """
3480        return self._native.measure()
3481
3482    @property
3483    def coefficients(self) -> Optional[Bmp280Coefficients]:
3484        """The trimming coefficients read at initialization, or ``None`` before it."""
3485        return self._native.coefficients
3486
3487
3488class Tmp117:
3489    """A Texas Instruments TMP117 driven over an :class:`~pamoja.hal.I2cBus`, converting on
3490    demand in one-shot mode and powered down between conversions.
3491
3492    >>> from pamoja.hal import I2cBus
3493    >>> bus = I2cBus.simulated([tmp117.sim.reporting(tmp117.ADDRESS_ADD0_GND, -18.5)])
3494    >>> Tmp117(bus, tmp117.ADDRESS_ADD0_GND).measure().celsius
3495    -18.5
3496    """
3497
3498    __slots__ = ("_native",)
3499
3500    def __init__(
3501        self, bus: I2cBus, address: int, *, averaging: Tmp117Averaging = Tmp117Averaging.X8
3502    ) -> None:
3503        """Make a driver for the part at ``address`` on ``bus``.
3504
3505        :param bus: The bus the part is on.
3506        :param address: One of the ``tmp117.ADDRESS_ADD0_*`` constants, by where ADD0 is
3507            tied.
3508        :param averaging: How many conversions are averaged into each result.
3509        """
3510        self._native = _NativeTmp117(bus._native, address, int(averaging))
3511
3512    def init(self) -> None:
3513        """Check the part is a TMP117, wait for its EEPROM, and write the settings with the
3514        part in shutdown.
3515
3516        :raises PamojaError: If nothing answers, the device id is not a TMP117's, or the
3517            EEPROM never reports ready.
3518        """
3519        self._native.init()
3520
3521    def measure(self) -> Tmp117Reading:
3522        """Run one conversion and read the temperature, initializing the part first if
3523        :meth:`init` has not run.
3524
3525        :returns: The temperature.
3526        :raises PamojaError: As :meth:`init`, and when the conversion never finishes.
3527        """
3528        return self._native.measure()
3529
3530    def set_alert_limits(self, high_celsius: float, low_celsius: float) -> None:
3531        """Write the high and low limits the part compares each result against.
3532
3533        :param high_celsius: The high limit; the factory value is 192 C.
3534        :param low_celsius: The low limit; the factory value is -256 C.
3535        :raises PamojaError: If the transfer fails.
3536        """
3537        self._native.set_alert_limits(high_celsius, low_celsius)
3538
3539    def alerts(self) -> Tmp117Alerts:
3540        """Read the alert flags, including results the driver's own reads saw since the
3541        last call.
3542
3543        :returns: Whether a result was above the high limit or below the low limit.
3544        :raises PamojaError: If the transfer fails.
3545        """
3546        return self._native.alerts()
3547
3548    @property
3549    def silicon_revision(self) -> Optional[int]:
3550        """The silicon revision read at initialization, or ``None`` before it."""
3551        return self._native.silicon_revision
3552
3553
3554class Opt3001:
3555    """A Texas Instruments OPT3001 driven over an :class:`~pamoja.hal.I2cBus`, measuring
3556    illuminance on demand in single-shot mode.
3557
3558    >>> from pamoja.hal import I2cBus
3559    >>> bus = I2cBus.simulated([opt3001.sim.reporting(opt3001.ADDRESS_GND, 1200.0)])
3560    >>> Opt3001(bus, opt3001.ADDRESS_GND).measure().lux
3561    1200.0
3562    """
3563
3564    __slots__ = ("_native",)
3565
3566    def __init__(
3567        self,
3568        bus: I2cBus,
3569        address: int,
3570        *,
3571        conversion_time: Opt3001ConversionTime = Opt3001ConversionTime.MS_800,
3572        range_number: int = 12,
3573    ) -> None:
3574        """Make a driver for the part at ``address`` on ``bus``.
3575
3576        :param bus: The bus the part is on.
3577        :param address: One of the ``opt3001.ADDRESS_*`` constants, by where ADDR is tied.
3578        :param conversion_time: How long each conversion integrates.
3579        :param range_number: A fixed full-scale range, ``0`` to ``11``, or ``12`` to let
3580            the part choose.
3581        """
3582        self._native = _NativeOpt3001(
3583            bus._native,
3584            address,
3585            Opt3001ConversionTime(conversion_time) == Opt3001ConversionTime.MS_800,
3586            range_number,
3587        )
3588
3589    def init(self) -> None:
3590        """Check the part is an OPT3001 and write the settings with the part in shutdown.
3591
3592        :raises PamojaError: If nothing answers, or either id register is not an OPT3001's.
3593        """
3594        self._native.init()
3595
3596    def measure(self) -> Opt3001Reading:
3597        """Run one conversion and read the illuminance, initializing the part first if
3598        :meth:`init` has not run.
3599
3600        :returns: The illuminance.
3601        :raises PamojaError: As :meth:`init`, and when the conversion never finishes.
3602        """
3603        return self._native.measure()
3604
3605    def set_limits(self, low_milli_lux: int, high_milli_lux: int) -> None:
3606        """Write the low and high limits the part's interrupt pin compares each result
3607        against.
3608
3609        :param low_milli_lux: The low limit, in millilux.
3610        :param high_milli_lux: The high limit, in millilux.
3611        :raises PamojaError: If the transfer fails.
3612        """
3613        self._native.set_limits(low_milli_lux, high_milli_lux)
3614
3615    @property
3616    def configuration(self) -> Opt3001Config:
3617        """The configuration the driver writes, with the part in shutdown."""
3618        return self._native.configuration
3619
3620
3621class Hdc1080:
3622    """A Texas Instruments HDC1080 driven over an :class:`~pamoja.hal.I2cBus`, measuring
3623    temperature then humidity from one trigger at its one address.
3624
3625    >>> from pamoja.hal import I2cBus
3626    >>> bus = I2cBus.simulated([hdc1080.sim.reporting(4.0, 91.0)])
3627    >>> round(Hdc1080(bus).measure().relative_humidity, 2)
3628    91.0
3629    """
3630
3631    __slots__ = ("_native",)
3632
3633    def __init__(
3634        self,
3635        bus: I2cBus,
3636        *,
3637        temperature_resolution: Hdc1080TemperatureResolution = (
3638            Hdc1080TemperatureResolution.BITS_14
3639        ),
3640        humidity_resolution: Hdc1080HumidityResolution = Hdc1080HumidityResolution.BITS_14,
3641    ) -> None:
3642        """Make a driver for the part on ``bus``.
3643
3644        :param bus: The bus the part is on.
3645        :param temperature_resolution: The temperature resolution, which sets its time.
3646        :param humidity_resolution: The humidity resolution, which sets its time.
3647        :raises ValueError: For a resolution the part does not have.
3648        """
3649        self._native = _NativeHdc1080(
3650            bus._native, int(temperature_resolution), int(humidity_resolution)
3651        )
3652
3653    def init(self) -> None:
3654        """Check the part is an HDC1080 and write the configuration.
3655
3656        :raises PamojaError: If nothing answers, or either id register is not an HDC1080's.
3657        """
3658        self._native.init()
3659
3660    def measure(self) -> Hdc1080Measurement:
3661        """Trigger one acquisition of both channels and read them, initializing the part
3662        first if :meth:`init` has not run.
3663
3664        :returns: The temperature and humidity.
3665        :raises PamojaError: As :meth:`init`, and when the part does not acknowledge the
3666            read, which it refuses until its results are ready.
3667        """
3668        return self._native.measure()
3669
3670    def heater(self, on: bool) -> None:
3671        """Switch the on-die heater, which runs only during acquisitions, on or off.
3672
3673        :param on: Whether the heater runs.
3674        :raises PamojaError: If the transfer fails.
3675        """
3676        self._native.heater(on)
3677
3678    @property
3679    def configuration(self) -> Hdc1080Config:
3680        """The configuration the driver writes."""
3681        return self._native.configuration
3682
3683
3684class Ina219:
3685    """A Texas Instruments INA219 driven over an :class:`~pamoja.hal.I2cBus`: shunt and bus
3686    voltage, current, and power on demand.
3687
3688    >>> from pamoja.hal import I2cBus
3689    >>> bus = I2cBus.simulated([ina219.sim.part(ina219.BASE_ADDRESS)])
3690    >>> Ina219(bus, ina219.BASE_ADDRESS).measure().bus_millivolts
3691    12000
3692    """
3693
3694    __slots__ = ("_native",)
3695
3696    def __init__(
3697        self,
3698        bus: I2cBus,
3699        address: int,
3700        *,
3701        shunt_milliohms: int = 100,
3702        max_microamps: int = 3_200_000,
3703        current_lsb_microamps: Optional[int] = None,
3704        config: Optional[Ina219Config] = None,
3705    ) -> None:
3706        """Make a driver for the part at ``address`` on ``bus``.
3707
3708        :param bus: The bus the part is on.
3709        :param address: ``ina219.BASE_ADDRESS`` plus what A1 and A0 add.
3710        :param shunt_milliohms: The shunt resistance; the common breakout's is 100.
3711        :param max_microamps: The largest current the shunt will carry, which sets the
3712            finest current step.
3713        :param current_lsb_microamps: A current step to use instead, such as a round 100.
3714        :param config: The range, gain, and converter settings; the power-on ones unless
3715            given.
3716        """
3717        self._native = _NativeIna219(
3718            bus._native,
3719            address,
3720            shunt_milliohms,
3721            max_microamps,
3722            current_lsb_microamps,
3723            config,
3724        )
3725
3726    def init(self) -> None:
3727        """Reset the part, write the configuration and the calibration, and read the
3728        calibration back, the identity check a part with no id register allows.
3729
3730        :raises PamojaError: If nothing answers, or the calibration does not hold.
3731        """
3732        self._native.init()
3733
3734    def measure(self) -> Ina219Reading:
3735        """Trigger one shunt and bus conversion and read every result, initializing the
3736        part first if :meth:`init` has not run.
3737
3738        :returns: The registers as read, and what they mean.
3739        :raises PamojaError: As :meth:`init`, and when the conversion-ready flag never sets.
3740        """
3741        return self._native.measure()
3742
3743    @property
3744    def current_lsb_microamps(self) -> int:
3745        """The current step the driver programs, in microamps per count."""
3746        return self._native.current_lsb_microamps
3747
3748    @property
3749    def calibration_word(self) -> int:
3750        """The calibration word the driver programs."""
3751        return self._native.calibration_word
3752
3753
3754class Ina226:
3755    """A Texas Instruments INA226 driven over an :class:`~pamoja.hal.I2cBus`: shunt and bus
3756    voltage, current, and power on demand.
3757
3758    >>> from pamoja.hal import I2cBus
3759    >>> bus = I2cBus.simulated([ina226.sim.part(ina226.BASE_ADDRESS)])
3760    >>> Ina226(bus, ina226.BASE_ADDRESS).measure().bus_microvolts
3761    12000000
3762    """
3763
3764    __slots__ = ("_native",)
3765
3766    def __init__(
3767        self,
3768        bus: I2cBus,
3769        address: int,
3770        *,
3771        shunt_milliohms: int = 100,
3772        max_microamps: int = 3_200_000,
3773        current_lsb_microamps: Optional[int] = None,
3774        config: Optional[Ina226Config] = None,
3775    ) -> None:
3776        """Make a driver for the part at ``address`` on ``bus``.
3777
3778        :param bus: The bus the part is on.
3779        :param address: The address A1 and A0 select, which ``ina226.address`` works out.
3780        :param shunt_milliohms: The shunt resistance.
3781        :param max_microamps: The largest current the shunt will carry, which sets the
3782            finest current step.
3783        :param current_lsb_microamps: A current step to use instead.
3784        :param config: The averaging and conversion times; the power-on ones unless given.
3785        """
3786        self._native = _NativeIna226(
3787            bus._native,
3788            address,
3789            shunt_milliohms,
3790            max_microamps,
3791            current_lsb_microamps,
3792            config,
3793        )
3794
3795    def init(self) -> None:
3796        """Reset the part, check it is an INA226, and program the configuration and
3797        calibration.
3798
3799        :raises PamojaError: If nothing answers, the id registers are not an INA226's, or
3800            the calibration does not read back.
3801        """
3802        self._native.init()
3803
3804    def measure(self) -> Ina226Reading:
3805        """Trigger one shunt and bus conversion and read every result, initializing the
3806        part first if :meth:`init` has not run.
3807
3808        :returns: The registers as read, and what they mean.
3809        :raises PamojaError: As :meth:`init`, and when the conversion-ready flag never sets.
3810        """
3811        return self._native.measure()
3812
3813    def set_alert(self, mask: Ina226MaskEnable, limit: int) -> None:
3814        """Program the alert pin: which limit it watches, and the limit.
3815
3816        :param mask: The mask/enable settings, one alert function at a time.
3817        :param limit: The alert-limit register, in the units of the register the function
3818            watches.
3819        :raises PamojaError: If the transfer fails.
3820        """
3821        self._native.set_alert(mask, limit)
3822
3823    @property
3824    def current_lsb_microamps(self) -> int:
3825        """The current step the driver programs, in microamps per count."""
3826        return self._native.current_lsb_microamps
3827
3828    @property
3829    def calibration_word(self) -> int:
3830        """The calibration word the driver programs."""
3831        return self._native.calibration_word
3832
3833    @property
3834    def identity(self) -> Optional[Ina226DieId]:
3835        """The die id read at initialization, or ``None`` before it."""
3836        return self._native.identity
3837
3838
3839class Ads1115:
3840    """A Texas Instruments ADS1115 driven over an :class:`~pamoja.hal.I2cBus`, converting
3841    one input on demand.
3842
3843    >>> from pamoja.hal import I2cBus
3844    >>> bus = I2cBus.simulated([ads1115.sim.part(ads1115.ADDRESS_GND)])
3845    >>> round(Ads1115(bus, ads1115.ADDRESS_GND).sample().volts, 3)
3846    1.65
3847    """
3848
3849    __slots__ = ("_native",)
3850
3851    def __init__(
3852        self,
3853        bus: I2cBus,
3854        address: int,
3855        *,
3856        mux: Ads1115Mux = Ads1115Mux.AIN0_AIN1,
3857        pga: Ads1115Pga = Ads1115Pga.FSR_2_048,
3858        data_rate: Ads1115DataRate = Ads1115DataRate.SPS_128,
3859    ) -> None:
3860        """Make a driver for the part at ``address`` on ``bus``.
3861
3862        :param bus: The bus the part is on.
3863        :param address: One of the ``ads1115.ADDRESS_*`` constants, by where ADDR is tied.
3864        :param mux: The input the part converts.
3865        :param pga: The full-scale range, and with it the size of one count.
3866        :param data_rate: The data rate, and with it the conversion time and the noise.
3867        """
3868        self._native = _NativeAds1115(
3869            bus._native, address, int(mux), int(pga), int(data_rate)
3870        )
3871
3872    def init(self) -> None:
3873        """Write the input, range, and data rate, and read the configuration back, the
3874        identity check a part with no id register allows.
3875
3876        :raises PamojaError: If nothing answers, or the configuration reads back
3877            differently.
3878        """
3879        self._native.init()
3880
3881    def sample(self) -> Ads1115Sample:
3882        """Run one conversion of the configured input, initializing the part first if
3883        :meth:`init` has not run.
3884
3885        :returns: The conversion, with the range it ran at.
3886        :raises PamojaError: As :meth:`init`, and when the conversion never finishes.
3887        """
3888        return self._native.sample()
3889
3890    def sample_input(self, mux: Ads1115Mux) -> Ads1115Sample:
3891        """Convert another input once, leaving the configured input as it was.
3892
3893        :param mux: The input for this one conversion.
3894        :returns: The conversion.
3895        :raises PamojaError: As :meth:`sample`.
3896        """
3897        return self._native.sample_input(int(mux))
3898
3899    @property
3900    def config(self) -> Ads1115Config:
3901        """The configuration the driver writes."""
3902        return self._native.config
3903
3904
3905class Sht3x:
3906    """A Sensirion SHT3x driven over an :class:`~pamoja.hal.I2cBus`, measuring on demand in
3907    single-shot mode.
3908
3909    >>> from pamoja.hal import I2cBus
3910    >>> bus = I2cBus.simulated([sht3x.sim.reporting(sht3x.ADDRESS_A, 30.0, 70.0)])
3911    >>> round(Sht3x(bus, sht3x.ADDRESS_A).measure().celsius, 1)
3912    30.0
3913    """
3914
3915    __slots__ = ("_native",)
3916
3917    def __init__(
3918        self,
3919        bus: I2cBus,
3920        address: int,
3921        *,
3922        repeatability: Sht3xRepeatability = Sht3xRepeatability.HIGH,
3923    ) -> None:
3924        """Make a driver for the part at ``address`` on ``bus``.
3925
3926        :param bus: The bus the part is on.
3927        :param address: ``sht3x.ADDRESS_A`` with ADDR low, ``sht3x.ADDRESS_B`` with it
3928            high.
3929        :param repeatability: How repeatable each measurement is, against how long it
3930            takes.
3931        """
3932        self._native = _NativeSht3x(
3933            bus._native, address, Sht3xRepeatability(repeatability).value
3934        )
3935
3936    def init(self) -> None:
3937        """Soft-reset the part and read its status; a status word whose checksum holds is
3938        what confirms an SHT3x answers, as the part has no id register.
3939
3940        :raises PamojaError: If nothing answers, or the status word fails its checksum.
3941        """
3942        self._native.init()
3943
3944    def measure(self) -> Sht3xMeasurement:
3945        """Run one single-shot measurement, initializing the part first if :meth:`init`
3946        has not run.
3947
3948        :returns: The checksum-checked temperature and humidity.
3949        :raises PamojaError: As :meth:`init`, and when a data word fails its checksum.
3950        """
3951        return self._native.measure()
3952
3953    def read_status(self) -> Sht3xStatus:
3954        """Read the status register, which :attr:`last_status` keeps as well.
3955
3956        :returns: The status.
3957        :raises PamojaError: If the transfer fails or the word fails its checksum.
3958        """
3959        return self._native.read_status()
3960
3961    def heater_on(self) -> None:
3962        """Switch the plausibility-check heater on, initializing the part first if needed.
3963
3964        :raises PamojaError: As :meth:`init`.
3965        """
3966        self._native.heater_on()
3967
3968    def heater_off(self) -> None:
3969        """Switch the heater off, which is its state after any reset.
3970
3971        :raises PamojaError: As :meth:`init`.
3972        """
3973        self._native.heater_off()
3974
3975    @property
3976    def last_status(self) -> Optional[Sht3xStatus]:
3977        """The status register as it was last read, or ``None`` before it has been."""
3978        return self._native.last_status
3979
3980
3981class Scd4x:
3982    """A Sensirion SCD40 or SCD41 driven over an :class:`~pamoja.hal.I2cBus` in periodic
3983    measurement, a result every five seconds.
3984
3985    >>> from pamoja.hal import I2cBus
3986    >>> bus = I2cBus.simulated([scd4x.sim.reporting(1450, 24.0, 55.0)])
3987    >>> Scd4x(bus).measure().co2_ppm
3988    1450
3989    """
3990
3991    __slots__ = ("_native",)
3992
3993    def __init__(self, bus: I2cBus) -> None:
3994        """Make a driver for the part on ``bus``, which has one address.
3995
3996        :param bus: The bus the part is on.
3997        """
3998        self._native = _NativeScd4x(bus._native)
3999
4000    def init(self) -> None:
4001        """Stop any running measurement, read the serial number, and start periodic
4002        measurement.
4003
4004        :raises PamojaError: If nothing answers, or the serial number fails its checksum.
4005        """
4006        self._native.init()
4007
4008    def measure(self) -> Scd4xMeasurement:
4009        """Wait for the next periodic result and read it, initializing the part first if
4010        :meth:`init` has not run.
4011
4012        :returns: The carbon dioxide, temperature, and humidity.
4013        :raises PamojaError: As :meth:`init`, when no result becomes ready, and when a word
4014            fails its checksum.
4015        """
4016        return self._native.measure()
4017
4018    def measure_single_shot(self) -> Scd4xMeasurement:
4019        """Run one on-demand measurement on an SCD41, which takes five seconds. The part
4020        must not be measuring periodically: call :meth:`stop` first, or use this in place
4021        of :meth:`init`.
4022
4023        :returns: The measurement.
4024        :raises PamojaError: As :meth:`measure`.
4025        """
4026        return self._native.measure_single_shot()
4027
4028    def data_ready(self) -> bool:
4029        """Ask the part whether a periodic result is waiting.
4030
4031        :returns: Whether :meth:`measure` would read without waiting.
4032        :raises PamojaError: If the transfer fails or the word fails its checksum.
4033        """
4034        return self._native.data_ready()
4035
4036    def stop(self) -> None:
4037        """Stop periodic measurement, after which the part takes its settings commands.
4038
4039        :raises PamojaError: If the transfer fails.
4040        """
4041        self._native.stop()
4042
4043    def start(self) -> None:
4044        """Start periodic measurement.
4045
4046        :raises PamojaError: If the transfer fails.
4047        """
4048        self._native.start()
4049
4050    def set_temperature_offset(self, milli_celsius: int) -> None:
4051        """Set the temperature offset that compensates the part's own warmth, until power
4052        is lost.
4053
4054        :param milli_celsius: The offset to subtract, in millidegrees.
4055        :raises PamojaError: If the transfer fails.
4056        """
4057        self._native.set_temperature_offset(milli_celsius)
4058
4059    def set_sensor_altitude(self, meters: int) -> None:
4060        """Set the altitude the part corrects its carbon dioxide reading for.
4061
4062        :param meters: The altitude above sea level.
4063        :raises PamojaError: If the transfer fails.
4064        """
4065        self._native.set_sensor_altitude(meters)
4066
4067    @property
4068    def serial(self) -> Optional[int]:
4069        """The 48-bit serial number read at initialization, or ``None`` before it."""
4070        return self._native.serial
4071
4072
4073class Ds18b20Thermometer:
4074    """A DS18B20 the Linux kernel serves as a ``w1_slave`` file.
4075
4076    On a Raspberry Pi the ``w1-gpio`` overlay (``dtoverlay=w1-gpio`` in ``config.txt``)
4077    puts a 1-Wire bus on GPIO 4, and the kernel lists every DS18B20 it finds under
4078    ``/sys/bus/w1/devices`` as a directory named by its family code and serial. Reading the
4079    directory's ``w1_slave`` file makes the kernel run a conversion and print the
4080    scratchpad, which :meth:`read` decodes. The file is only text, so a test can write one
4081    anywhere and read it with :meth:`at`.
4082    """
4083
4084    __slots__ = ("_native",)
4085
4086    def __init__(self, native: _NativeDs18b20Thermometer) -> None:
4087        """Wrap a native thermometer. Use :meth:`for_serial`, :meth:`at`, or
4088        :meth:`discover`."""
4089        self._native = native
4090
4091    @classmethod
4092    def for_serial(cls, serial: str) -> Ds18b20Thermometer:
4093        """Name a thermometer by the serial in its directory name.
4094
4095        :param serial: The twelve hex digits after ``28-``.
4096        :returns: The thermometer, reading ``/sys/bus/w1/devices/28-<serial>/w1_slave``.
4097        """
4098        return cls(_NativeDs18b20Thermometer.for_serial(serial))
4099
4100    @classmethod
4101    def at(cls, path: str) -> Ds18b20Thermometer:
4102        """Name a thermometer by the path of its ``w1_slave`` file.
4103
4104        :param path: The file to read.
4105        :returns: The thermometer.
4106        """
4107        return cls(_NativeDs18b20Thermometer.at(str(path)))
4108
4109    @classmethod
4110    def discover(cls, devices: Optional[str] = None) -> List[Ds18b20Thermometer]:
4111        """List every DS18B20 the kernel has found, one per ``28-`` directory.
4112
4113        :param devices: The directory the kernel lists its 1-Wire devices in, or ``None``
4114            for ``/sys/bus/w1/devices``.
4115        :returns: The thermometers, sorted by directory name.
4116        :raises PamojaError: If the directory cannot be listed, which usually means the
4117            1-Wire overlay is off.
4118        """
4119        found = _NativeDs18b20Thermometer.discover(None if devices is None else str(devices))
4120        return [cls(native) for native in found]
4121
4122    @property
4123    def path(self) -> str:
4124        """The path of the file the thermometer reads."""
4125        return self._native.path
4126
4127    @property
4128    def serial(self) -> Optional[str]:
4129        """The serial the kernel named the thermometer's directory after.
4130
4131        The twelve hex digits after ``28-``, which tell one probe from another and stay with
4132        the part for life, or ``None`` when the file does not sit in a DS18B20's directory, as
4133        one named by :meth:`at` may not.
4134
4135        >>> Ds18b20Thermometer.for_serial("000005e2fdc3").serial
4136        '000005e2fdc3'
4137        >>> Ds18b20Thermometer.at("/tmp/w1_slave").serial is None
4138        True
4139        """
4140        return self._native.serial
4141
4142    def read(self) -> Ds18b20Reading:
4143        """Read the file, which makes the kernel run a conversion, and decode it.
4144
4145        :returns: The checksum-checked reading.
4146        :raises PamojaError: If the file cannot be read, because the overlay is off, the
4147            probe is gone, or the process may not read it; or if the kernel or this decoder
4148            rejects the checksum.
4149        """
4150        return self._native.read()
4151
4152
4153#: A Bosch BME280 temperature, pressure, and humidity sensor.
4154bme280 = _Bme280()
4155
4156#: A Maxim DS18B20 1-Wire thermometer.
4157ds18b20 = _Ds18b20()
4158
4159#: A TI INA219 current, voltage, and power monitor.
4160ina219 = _Ina219()
4161
4162#: A TI ADS1115 16-bit analog-to-digital converter.
4163ads1115 = _Ads1115()
4164
4165#: A Bosch BMP280 pressure and temperature sensor.
4166bmp280 = _Bmp280()
4167
4168#: A Sensirion SHT30, SHT31, or SHT35 temperature and humidity sensor.
4169sht3x = _Sht3x()
4170
4171#: A Sensirion SCD40 or SCD41 carbon dioxide, temperature, and humidity sensor.
4172scd4x = _Scd4x()
4173
4174#: A TI TMP117 precision thermometer.
4175tmp117 = _Tmp117()
4176
4177#: A TI HDC1080 temperature and humidity sensor.
4178hdc1080 = _Hdc1080()
4179
4180#: A TI OPT3001 ambient light sensor.
4181opt3001 = _Opt3001()
4182
4183#: A TI INA226 current, voltage, and power monitor.
4184ina226 = _Ina226()
class Ads1115:
3840class Ads1115:
3841    """A Texas Instruments ADS1115 driven over an :class:`~pamoja.hal.I2cBus`, converting
3842    one input on demand.
3843
3844    >>> from pamoja.hal import I2cBus
3845    >>> bus = I2cBus.simulated([ads1115.sim.part(ads1115.ADDRESS_GND)])
3846    >>> round(Ads1115(bus, ads1115.ADDRESS_GND).sample().volts, 3)
3847    1.65
3848    """
3849
3850    __slots__ = ("_native",)
3851
3852    def __init__(
3853        self,
3854        bus: I2cBus,
3855        address: int,
3856        *,
3857        mux: Ads1115Mux = Ads1115Mux.AIN0_AIN1,
3858        pga: Ads1115Pga = Ads1115Pga.FSR_2_048,
3859        data_rate: Ads1115DataRate = Ads1115DataRate.SPS_128,
3860    ) -> None:
3861        """Make a driver for the part at ``address`` on ``bus``.
3862
3863        :param bus: The bus the part is on.
3864        :param address: One of the ``ads1115.ADDRESS_*`` constants, by where ADDR is tied.
3865        :param mux: The input the part converts.
3866        :param pga: The full-scale range, and with it the size of one count.
3867        :param data_rate: The data rate, and with it the conversion time and the noise.
3868        """
3869        self._native = _NativeAds1115(
3870            bus._native, address, int(mux), int(pga), int(data_rate)
3871        )
3872
3873    def init(self) -> None:
3874        """Write the input, range, and data rate, and read the configuration back, the
3875        identity check a part with no id register allows.
3876
3877        :raises PamojaError: If nothing answers, or the configuration reads back
3878            differently.
3879        """
3880        self._native.init()
3881
3882    def sample(self) -> Ads1115Sample:
3883        """Run one conversion of the configured input, initializing the part first if
3884        :meth:`init` has not run.
3885
3886        :returns: The conversion, with the range it ran at.
3887        :raises PamojaError: As :meth:`init`, and when the conversion never finishes.
3888        """
3889        return self._native.sample()
3890
3891    def sample_input(self, mux: Ads1115Mux) -> Ads1115Sample:
3892        """Convert another input once, leaving the configured input as it was.
3893
3894        :param mux: The input for this one conversion.
3895        :returns: The conversion.
3896        :raises PamojaError: As :meth:`sample`.
3897        """
3898        return self._native.sample_input(int(mux))
3899
3900    @property
3901    def config(self) -> Ads1115Config:
3902        """The configuration the driver writes."""
3903        return self._native.config

A Texas Instruments ADS1115 driven over an ~pamoja.hal.I2cBus, converting one input on demand.

>>> from pamoja.hal import I2cBus
>>> bus = I2cBus.simulated([ads1115.sim.part(ads1115.ADDRESS_GND)])
>>> round(Ads1115(bus, ads1115.ADDRESS_GND).sample().volts, 3)
1.65
Ads1115( bus: pamoja.hal.I2cBus, address: int, *, mux: Ads1115Mux = <Ads1115Mux.AIN0_AIN1: 0>, pga: Ads1115Pga = <Ads1115Pga.FSR_2_048: 2>, data_rate: Ads1115DataRate = <Ads1115DataRate.SPS_128: 4>)
3852    def __init__(
3853        self,
3854        bus: I2cBus,
3855        address: int,
3856        *,
3857        mux: Ads1115Mux = Ads1115Mux.AIN0_AIN1,
3858        pga: Ads1115Pga = Ads1115Pga.FSR_2_048,
3859        data_rate: Ads1115DataRate = Ads1115DataRate.SPS_128,
3860    ) -> None:
3861        """Make a driver for the part at ``address`` on ``bus``.
3862
3863        :param bus: The bus the part is on.
3864        :param address: One of the ``ads1115.ADDRESS_*`` constants, by where ADDR is tied.
3865        :param mux: The input the part converts.
3866        :param pga: The full-scale range, and with it the size of one count.
3867        :param data_rate: The data rate, and with it the conversion time and the noise.
3868        """
3869        self._native = _NativeAds1115(
3870            bus._native, address, int(mux), int(pga), int(data_rate)
3871        )

Make a driver for the part at address on bus.

Parameters
  • bus: The bus the part is on.
  • address: One of the ads1115.ADDRESS_* constants, by where ADDR is tied.
  • mux: The input the part converts.
  • pga: The full-scale range, and with it the size of one count.
  • data_rate: The data rate, and with it the conversion time and the noise.
def init(self) -> None:
3873    def init(self) -> None:
3874        """Write the input, range, and data rate, and read the configuration back, the
3875        identity check a part with no id register allows.
3876
3877        :raises PamojaError: If nothing answers, or the configuration reads back
3878            differently.
3879        """
3880        self._native.init()

Write the input, range, and data rate, and read the configuration back, the identity check a part with no id register allows.

Raises
  • PamojaError: If nothing answers, or the configuration reads back differently.
def sample(self) -> Ads1115Sample:
3882    def sample(self) -> Ads1115Sample:
3883        """Run one conversion of the configured input, initializing the part first if
3884        :meth:`init` has not run.
3885
3886        :returns: The conversion, with the range it ran at.
3887        :raises PamojaError: As :meth:`init`, and when the conversion never finishes.
3888        """
3889        return self._native.sample()

Run one conversion of the configured input, initializing the part first if init() has not run.

:returns: The conversion, with the range it ran at.

Raises
  • PamojaError: As init(), and when the conversion never finishes.
def sample_input(self, mux: Ads1115Mux) -> Ads1115Sample:
3891    def sample_input(self, mux: Ads1115Mux) -> Ads1115Sample:
3892        """Convert another input once, leaving the configured input as it was.
3893
3894        :param mux: The input for this one conversion.
3895        :returns: The conversion.
3896        :raises PamojaError: As :meth:`sample`.
3897        """
3898        return self._native.sample_input(int(mux))

Convert another input once, leaving the configured input as it was.

Parameters
  • mux: The input for this one conversion. :returns: The conversion.
Raises
config: Ads1115Config
3900    @property
3901    def config(self) -> Ads1115Config:
3902        """The configuration the driver writes."""
3903        return self._native.config

The configuration the driver writes.

class Ads1115Config:

An ADS1115 configuration register, field by field.

comparator_queue

The comparator queue code, 0..=3, where 3 disables the comparator.

start_conversion

Whether writing this starts a single conversion.

data_rate

The data rate code, 0..=7.

mux

The input multiplexer code, 0..=7.

window_comparator

Whether to use the window comparator rather than the traditional one.

comparator_active_high

Whether the ALERT/RDY pin is active high.

comparator_latching

Whether the comparator latches until the conversion is read.

single_shot

Whether to convert once per request and power down, rather than continuously.

pga

The gain code, 0..=7, which sets the full-scale range.

class Ads1115DataRate(enum.IntEnum):
673class Ads1115DataRate(enum.IntEnum):
674    """An ADS1115 data rate, as its register code."""
675
676    #: 8 samples per second.
677    SPS_8 = 0
678    #: 16 samples per second.
679    SPS_16 = 1
680    #: 32 samples per second.
681    SPS_32 = 2
682    #: 64 samples per second.
683    SPS_64 = 3
684    #: 128 samples per second, the reset setting.
685    SPS_128 = 4
686    #: 250 samples per second.
687    SPS_250 = 5
688    #: 475 samples per second.
689    SPS_475 = 6
690    #: 860 samples per second.
691    SPS_860 = 7

An ADS1115 data rate, as its register code.

SPS_8 = <Ads1115DataRate.SPS_8: 0>
SPS_16 = <Ads1115DataRate.SPS_16: 1>
SPS_32 = <Ads1115DataRate.SPS_32: 2>
SPS_64 = <Ads1115DataRate.SPS_64: 3>
SPS_128 = <Ads1115DataRate.SPS_128: 4>
SPS_250 = <Ads1115DataRate.SPS_250: 5>
SPS_475 = <Ads1115DataRate.SPS_475: 6>
SPS_860 = <Ads1115DataRate.SPS_860: 7>
class Ads1115Mux(enum.IntEnum):
635class Ads1115Mux(enum.IntEnum):
636    """An ADS1115 input multiplexer setting, as its register code."""
637
638    #: AIN0 against AIN1, the reset setting.
639    AIN0_AIN1 = 0
640    #: AIN0 against AIN3.
641    AIN0_AIN3 = 1
642    #: AIN1 against AIN3.
643    AIN1_AIN3 = 2
644    #: AIN2 against AIN3.
645    AIN2_AIN3 = 3
646    #: AIN0 against ground.
647    AIN0_GND = 4
648    #: AIN1 against ground.
649    AIN1_GND = 5
650    #: AIN2 against ground.
651    AIN2_GND = 6
652    #: AIN3 against ground.
653    AIN3_GND = 7

An ADS1115 input multiplexer setting, as its register code.

AIN0_AIN1 = <Ads1115Mux.AIN0_AIN1: 0>
AIN0_AIN3 = <Ads1115Mux.AIN0_AIN3: 1>
AIN1_AIN3 = <Ads1115Mux.AIN1_AIN3: 2>
AIN2_AIN3 = <Ads1115Mux.AIN2_AIN3: 3>
AIN0_GND = <Ads1115Mux.AIN0_GND: 4>
AIN1_GND = <Ads1115Mux.AIN1_GND: 5>
AIN2_GND = <Ads1115Mux.AIN2_GND: 6>
AIN3_GND = <Ads1115Mux.AIN3_GND: 7>
class Ads1115Pga(enum.IntEnum):
656class Ads1115Pga(enum.IntEnum):
657    """An ADS1115 full-scale range, as its register code."""
658
659    #: 6.144 V either side of zero.
660    FSR_6_144 = 0
661    #: 4.096 V.
662    FSR_4_096 = 1
663    #: 2.048 V, the reset setting.
664    FSR_2_048 = 2
665    #: 1.024 V.
666    FSR_1_024 = 3
667    #: 0.512 V.
668    FSR_0_512 = 4
669    #: 0.256 V.
670    FSR_0_256 = 5

An ADS1115 full-scale range, as its register code.

FSR_6_144 = <Ads1115Pga.FSR_6_144: 0>
FSR_4_096 = <Ads1115Pga.FSR_4_096: 1>
FSR_2_048 = <Ads1115Pga.FSR_2_048: 2>
FSR_1_024 = <Ads1115Pga.FSR_1_024: 3>
FSR_0_512 = <Ads1115Pga.FSR_0_512: 4>
FSR_0_256 = <Ads1115Pga.FSR_0_256: 5>
class Ads1115Sample:

One ADS1115 conversion.

nanovolts

The voltage in nanovolts, exact in integer arithmetic.

volts

The voltage in volts.

clipped

Whether the conversion sits at an end code, where the output clips for a signal past the range, so the voltage is a bound rather than the reading.

raw

The conversion register, two's complement.

pga

The gain code the conversion ran at.

class Bme280:
694class Bme280:
695    """A Bosch BME280 driven over an :class:`~pamoja.hal.I2cBus`, measuring on demand in
696    forced mode.
697
698    Nothing is sent until :meth:`init` or the first :meth:`measure`. The driver holds its
699    own share of the bus, and releases the interpreter while the part answers.
700
701    >>> from pamoja.hal import I2cBus
702    >>> bus = I2cBus.simulated([bme280.sim.part(bme280.ADDRESS_PRIMARY)])
703    >>> sensor = Bme280(bus, bme280.ADDRESS_PRIMARY)
704    >>> f"{sensor.measure().celsius:.2f}"
705    '20.44'
706    """
707
708    __slots__ = ("_native",)
709
710    def __init__(
711        self,
712        bus: I2cBus,
713        address: int,
714        *,
715        temperature: Bme280Oversampling = Bme280Oversampling.X1,
716        pressure: Bme280Oversampling = Bme280Oversampling.X1,
717        humidity: Bme280Oversampling = Bme280Oversampling.X1,
718        filter: Bme280Filter = Bme280Filter.OFF,
719    ) -> None:
720        """Make a driver for the part at ``address`` on ``bus``.
721
722        :param bus: The bus the part is on.
723        :param address: ``bme280.ADDRESS_PRIMARY`` with SDO low, or
724            ``bme280.ADDRESS_SECONDARY`` with SDO high.
725        :param temperature: The temperature oversampling.
726        :param pressure: The pressure oversampling.
727        :param humidity: The humidity oversampling.
728        :param filter: The IIR filter.
729        """
730        self._native = _NativeBme280(
731            bus._native,
732            address,
733            int(temperature),
734            int(pressure),
735            int(humidity),
736            int(filter),
737        )
738
739    def init(self) -> None:
740        """Reset the part, check it is a BME280, read its calibration, and write the
741        settings in the order the datasheet requires, leaving the part asleep.
742
743        :raises PamojaError: If nothing answers at the address, another part does, or
744            the calibration never finishes loading.
745        """
746        self._native.init()
747
748    def measure(self) -> Bme280Measurement:
749        """Run one forced measurement and compensate it, initializing the part first if
750        :meth:`init` has not run.
751
752        :returns: The reading.
753        :raises PamojaError: As :meth:`init`, and when the part is still measuring after
754            the datasheet's time.
755        """
756        return self._native.measure()

A Bosch BME280 driven over an ~pamoja.hal.I2cBus, measuring on demand in forced mode.

Nothing is sent until init() or the first measure(). The driver holds its own share of the bus, and releases the interpreter while the part answers.

>>> from pamoja.hal import I2cBus
>>> bus = I2cBus.simulated([bme280.sim.part(bme280.ADDRESS_PRIMARY)])
>>> sensor = Bme280(bus, bme280.ADDRESS_PRIMARY)
>>> f"{sensor.measure().celsius:.2f}"
'20.44'
Bme280( bus: pamoja.hal.I2cBus, address: int, *, temperature: Bme280Oversampling = <Bme280Oversampling.X1: 1>, pressure: Bme280Oversampling = <Bme280Oversampling.X1: 1>, humidity: Bme280Oversampling = <Bme280Oversampling.X1: 1>, filter: Bme280Filter = <Bme280Filter.OFF: 0>)
710    def __init__(
711        self,
712        bus: I2cBus,
713        address: int,
714        *,
715        temperature: Bme280Oversampling = Bme280Oversampling.X1,
716        pressure: Bme280Oversampling = Bme280Oversampling.X1,
717        humidity: Bme280Oversampling = Bme280Oversampling.X1,
718        filter: Bme280Filter = Bme280Filter.OFF,
719    ) -> None:
720        """Make a driver for the part at ``address`` on ``bus``.
721
722        :param bus: The bus the part is on.
723        :param address: ``bme280.ADDRESS_PRIMARY`` with SDO low, or
724            ``bme280.ADDRESS_SECONDARY`` with SDO high.
725        :param temperature: The temperature oversampling.
726        :param pressure: The pressure oversampling.
727        :param humidity: The humidity oversampling.
728        :param filter: The IIR filter.
729        """
730        self._native = _NativeBme280(
731            bus._native,
732            address,
733            int(temperature),
734            int(pressure),
735            int(humidity),
736            int(filter),
737        )

Make a driver for the part at address on bus.

Parameters
  • bus: The bus the part is on.
  • address: bme280.ADDRESS_PRIMARY with SDO low, or bme280.ADDRESS_SECONDARY with SDO high.
  • temperature: The temperature oversampling.
  • pressure: The pressure oversampling.
  • humidity: The humidity oversampling.
  • filter: The IIR filter.
def init(self) -> None:
739    def init(self) -> None:
740        """Reset the part, check it is a BME280, read its calibration, and write the
741        settings in the order the datasheet requires, leaving the part asleep.
742
743        :raises PamojaError: If nothing answers at the address, another part does, or
744            the calibration never finishes loading.
745        """
746        self._native.init()

Reset the part, check it is a BME280, read its calibration, and write the settings in the order the datasheet requires, leaving the part asleep.

Raises
  • PamojaError: If nothing answers at the address, another part does, or the calibration never finishes loading.
def measure(self) -> Bme280Measurement:
748    def measure(self) -> Bme280Measurement:
749        """Run one forced measurement and compensate it, initializing the part first if
750        :meth:`init` has not run.
751
752        :returns: The reading.
753        :raises PamojaError: As :meth:`init`, and when the part is still measuring after
754            the datasheet's time.
755        """
756        return self._native.measure()

Run one forced measurement and compensate it, initializing the part first if init() has not run.

:returns: The reading.

Raises
  • PamojaError: As init(), and when the part is still measuring after the datasheet's time.
class Bme280Calibration:

A BME280's factory calibration, read once and reused for every measurement.

def compensate(self, /, measurement):

Turns an eight-byte burst read into a compensated reading.

class Bme280Config:

A BME280 config register, field by field.

standby

The normal-mode standby code, 0..=7.

filter

The IIR filter code, 0..=4, where 0 is off.

spi_3wire

Whether the 3-wire SPI interface is enabled.

class Bme280CtrlMeas:

A BME280 ctrl_meas register, field by field.

mode

The power mode code: 0 sleep, 1 forced, 3 normal.

temperature

The temperature oversampling code, 0..=5, where 0 skips the measurement.

pressure

The pressure oversampling code, 0..=5, where 0 skips the measurement.

class Bme280Filter(enum.IntEnum):
409class Bme280Filter(enum.IntEnum):
410    """The IIR filter that smooths a BME280's pressure and temperature, as its code."""
411
412    #: No filtering.
413    OFF = 0
414    #: Coefficient 2.
415    X2 = 1
416    #: Coefficient 4.
417    X4 = 2
418    #: Coefficient 8.
419    X8 = 3
420    #: Coefficient 16.
421    X16 = 4

The IIR filter that smooths a BME280's pressure and temperature, as its code.

OFF = <Bme280Filter.OFF: 0>
X2 = <Bme280Filter.X2: 1>
X4 = <Bme280Filter.X4: 2>
X8 = <Bme280Filter.X8: 3>
X16 = <Bme280Filter.X16: 4>
class Bme280Measurement:

A compensated BME280 reading.

celsius

The temperature in degrees Celsius.

relative_humidity_percent

The relative humidity as a percentage.

hectopascals

The pressure in hectopascals, the unit a barometer is usually quoted in.

pascals

The pressure in pascals.

class Bme280Mode(enum.IntEnum):
398class Bme280Mode(enum.IntEnum):
399    """A BME280 power mode, as its register code."""
400
401    #: No measurements; the power-on default.
402    SLEEP = 0
403    #: One measurement, then back to sleep.
404    FORCED = 1
405    #: Measurements on a cycle, a standby period apart.
406    NORMAL = 3

A BME280 power mode, as its register code.

SLEEP = <Bme280Mode.SLEEP: 0>
FORCED = <Bme280Mode.FORCED: 1>
NORMAL = <Bme280Mode.NORMAL: 3>
class Bme280Oversampling(enum.IntEnum):
381class Bme280Oversampling(enum.IntEnum):
382    """How many samples a BME280 measurement averages, as its register code."""
383
384    #: The measurement is skipped.
385    SKIPPED = 0
386    #: One sample.
387    X1 = 1
388    #: Two samples.
389    X2 = 2
390    #: Four samples.
391    X4 = 3
392    #: Eight samples.
393    X8 = 4
394    #: Sixteen samples.
395    X16 = 5

How many samples a BME280 measurement averages, as its register code.

class Bme280Standby(enum.IntEnum):
424class Bme280Standby(enum.IntEnum):
425    """The period a BME280 in normal mode rests between measurements, as its code."""
426
427    #: 0.5 ms.
428    MS_0_5 = 0
429    #: 62.5 ms.
430    MS_62_5 = 1
431    #: 125 ms.
432    MS_125 = 2
433    #: 250 ms.
434    MS_250 = 3
435    #: 500 ms.
436    MS_500 = 4
437    #: 1000 ms.
438    MS_1000 = 5
439    #: 10 ms.
440    MS_10 = 6
441    #: 20 ms.
442    MS_20 = 7

The period a BME280 in normal mode rests between measurements, as its code.

MS_0_5 = <Bme280Standby.MS_0_5: 0>
MS_62_5 = <Bme280Standby.MS_62_5: 1>
MS_125 = <Bme280Standby.MS_125: 2>
MS_250 = <Bme280Standby.MS_250: 3>
MS_500 = <Bme280Standby.MS_500: 4>
MS_1000 = <Bme280Standby.MS_1000: 5>
MS_10 = <Bme280Standby.MS_10: 6>
MS_20 = <Bme280Standby.MS_20: 7>
class Bmp280:
3426class Bmp280:
3427    """A Bosch BMP280 driven over an :class:`~pamoja.hal.I2cBus`, measuring on demand in
3428    forced mode.
3429
3430    Nothing is sent until :meth:`init` or the first :meth:`measure`. The driver holds its
3431    own share of the bus, and releases the interpreter while the part answers.
3432
3433    >>> from pamoja.hal import I2cBus
3434    >>> bus = I2cBus.simulated([bmp280.sim.part(bmp280.ADDRESS_PRIMARY)])
3435    >>> f"{Bmp280(bus, bmp280.ADDRESS_PRIMARY).measure().celsius:.2f}"
3436    '20.44'
3437    """
3438
3439    __slots__ = ("_native",)
3440
3441    def __init__(
3442        self,
3443        bus: I2cBus,
3444        address: int,
3445        *,
3446        temperature: Bmp280Oversampling = Bmp280Oversampling.X1,
3447        pressure: Bmp280Oversampling = Bmp280Oversampling.X1,
3448        filter: int = 0,
3449    ) -> None:
3450        """Make a driver for the part at ``address`` on ``bus``.
3451
3452        :param bus: The bus the part is on.
3453        :param address: ``bmp280.ADDRESS_PRIMARY`` with SDO low, or
3454            ``bmp280.ADDRESS_SECONDARY`` with SDO high.
3455        :param temperature: The temperature oversampling.
3456        :param pressure: The pressure oversampling.
3457        :param filter: The IIR filter's three-bit code, ``0`` for the filter off, written
3458            as given.
3459        """
3460        self._native = _NativeBmp280(
3461            bus._native, address, int(temperature), int(pressure), int(filter)
3462        )
3463
3464    def init(self) -> None:
3465        """Reset the part, check it is a BMP280, read its trimming, and write the settings,
3466        leaving the part asleep.
3467
3468        :raises PamojaError: If nothing answers at the address, another part does, or the
3469            trimming never finishes loading.
3470        """
3471        self._native.init()
3472
3473    def measure(self) -> Bmp280Reading:
3474        """Run one forced measurement and compensate it, initializing the part first if
3475        :meth:`init` has not run.
3476
3477        :returns: The reading.
3478        :raises PamojaError: As :meth:`init`, and when the part is still measuring after
3479            the datasheet's time.
3480        """
3481        return self._native.measure()
3482
3483    @property
3484    def coefficients(self) -> Optional[Bmp280Coefficients]:
3485        """The trimming coefficients read at initialization, or ``None`` before it."""
3486        return self._native.coefficients

A Bosch BMP280 driven over an ~pamoja.hal.I2cBus, measuring on demand in forced mode.

Nothing is sent until init() or the first measure(). The driver holds its own share of the bus, and releases the interpreter while the part answers.

>>> from pamoja.hal import I2cBus
>>> bus = I2cBus.simulated([bmp280.sim.part(bmp280.ADDRESS_PRIMARY)])
>>> f"{Bmp280(bus, bmp280.ADDRESS_PRIMARY).measure().celsius:.2f}"
'20.44'
Bmp280( bus: pamoja.hal.I2cBus, address: int, *, temperature: Bmp280Oversampling = <Bmp280Oversampling.X1: 1>, pressure: Bmp280Oversampling = <Bmp280Oversampling.X1: 1>, filter: int = 0)
3441    def __init__(
3442        self,
3443        bus: I2cBus,
3444        address: int,
3445        *,
3446        temperature: Bmp280Oversampling = Bmp280Oversampling.X1,
3447        pressure: Bmp280Oversampling = Bmp280Oversampling.X1,
3448        filter: int = 0,
3449    ) -> None:
3450        """Make a driver for the part at ``address`` on ``bus``.
3451
3452        :param bus: The bus the part is on.
3453        :param address: ``bmp280.ADDRESS_PRIMARY`` with SDO low, or
3454            ``bmp280.ADDRESS_SECONDARY`` with SDO high.
3455        :param temperature: The temperature oversampling.
3456        :param pressure: The pressure oversampling.
3457        :param filter: The IIR filter's three-bit code, ``0`` for the filter off, written
3458            as given.
3459        """
3460        self._native = _NativeBmp280(
3461            bus._native, address, int(temperature), int(pressure), int(filter)
3462        )

Make a driver for the part at address on bus.

Parameters
  • bus: The bus the part is on.
  • address: bmp280.ADDRESS_PRIMARY with SDO low, or bmp280.ADDRESS_SECONDARY with SDO high.
  • temperature: The temperature oversampling.
  • pressure: The pressure oversampling.
  • filter: The IIR filter's three-bit code, 0 for the filter off, written as given.
def init(self) -> None:
3464    def init(self) -> None:
3465        """Reset the part, check it is a BMP280, read its trimming, and write the settings,
3466        leaving the part asleep.
3467
3468        :raises PamojaError: If nothing answers at the address, another part does, or the
3469            trimming never finishes loading.
3470        """
3471        self._native.init()

Reset the part, check it is a BMP280, read its trimming, and write the settings, leaving the part asleep.

Raises
  • PamojaError: If nothing answers at the address, another part does, or the trimming never finishes loading.
def measure(self) -> Bmp280Reading:
3473    def measure(self) -> Bmp280Reading:
3474        """Run one forced measurement and compensate it, initializing the part first if
3475        :meth:`init` has not run.
3476
3477        :returns: The reading.
3478        :raises PamojaError: As :meth:`init`, and when the part is still measuring after
3479            the datasheet's time.
3480        """
3481        return self._native.measure()

Run one forced measurement and compensate it, initializing the part first if init() has not run.

:returns: The reading.

Raises
  • PamojaError: As init(), and when the part is still measuring after the datasheet's time.
coefficients: Optional[Bmp280Coefficients]
3483    @property
3484    def coefficients(self) -> Optional[Bmp280Coefficients]:
3485        """The trimming coefficients read at initialization, or ``None`` before it."""
3486        return self._native.coefficients

The trimming coefficients read at initialization, or None before it.

class Bmp280Calibration:

A BMP280's factory calibration, read once and reused for every measurement.

def compensate(self, /, measurement):

Turns a six-byte burst read into a compensated reading.

def to_bytes(self, /):

Rebuilds the 24 calibration bytes a device holding these coefficients returns.

coefficients

The trimming coefficients the calibration bytes carried.

class Bmp280Coefficients:

A BMP280's per-chip trimming coefficients, as they sit in its registers.

dig_p2

The dig_P2 coefficient.

dig_t2

The dig_T2 coefficient.

dig_p3

The dig_P3 coefficient.

dig_p4

The dig_P4 coefficient.

dig_t3

The dig_T3 coefficient.

dig_p6

The dig_P6 coefficient.

dig_p7

The dig_P7 coefficient.

dig_p9

The dig_P9 coefficient.

dig_t1

The dig_T1 coefficient.

dig_p1

The dig_P1 coefficient.

dig_p5

The dig_P5 coefficient.

dig_p8

The dig_P8 coefficient.

class Bmp280Config:

A BMP280 config register, field by field.

standby

The normal-mode standby code, 0..=7.

filter

The IIR filter code, 0..=7.

spi_3wire

Whether the 3-wire SPI interface is enabled.

class Bmp280CtrlMeas:

A BMP280 ctrl_meas register, field by field.

pressure

The pressure oversampling code, 0..=5, where 0 skips the measurement.

mode

The power mode code: 0 sleep, 1 forced, 3 normal.

temperature

The temperature oversampling code, 0..=5, where 0 skips the measurement.

class Bmp280Oversampling(enum.IntEnum):
445class Bmp280Oversampling(enum.IntEnum):
446    """How many samples a BMP280 measurement averages, as its register code."""
447
448    #: The measurement is skipped.
449    SKIPPED = 0
450    #: One sample.
451    X1 = 1
452    #: Two samples.
453    X2 = 2
454    #: Four samples.
455    X4 = 3
456    #: Eight samples.
457    X8 = 4
458    #: Sixteen samples.
459    X16 = 5

How many samples a BMP280 measurement averages, as its register code.

class Bmp280RawMeasurement:

The uncompensated codes a BMP280 burst read carries.

pressure_skipped

Whether pressure oversampling was off, so the code carries no reading.

temperature

The 20-bit temperature code.

temperature_skipped

Whether temperature oversampling was off, so the code carries no reading.

pressure

The 20-bit pressure code.

class Bmp280Reading:

A compensated BMP280 reading.

hectopascals

The pressure in hectopascals, the unit a barometer is usually quoted in.

celsius

The temperature in degrees Celsius.

pascals

The pressure in pascals.

class Ds18b20Reading:

A decoded DS18B20 scratchpad.

alarm_low

The low alarm threshold in whole degrees Celsius.

raw_temperature

The raw temperature register, 1/16 degree Celsius per count.

alarm_high

The high alarm threshold in whole degrees Celsius.

micro_celsius

The temperature in micro-degrees Celsius, exact in integer arithmetic.

resolution_bits

The configured resolution, as a number of bits: 9, 10, 11, or 12.

celsius

The temperature in degrees Celsius.

class Ds18b20Thermometer:
4074class Ds18b20Thermometer:
4075    """A DS18B20 the Linux kernel serves as a ``w1_slave`` file.
4076
4077    On a Raspberry Pi the ``w1-gpio`` overlay (``dtoverlay=w1-gpio`` in ``config.txt``)
4078    puts a 1-Wire bus on GPIO 4, and the kernel lists every DS18B20 it finds under
4079    ``/sys/bus/w1/devices`` as a directory named by its family code and serial. Reading the
4080    directory's ``w1_slave`` file makes the kernel run a conversion and print the
4081    scratchpad, which :meth:`read` decodes. The file is only text, so a test can write one
4082    anywhere and read it with :meth:`at`.
4083    """
4084
4085    __slots__ = ("_native",)
4086
4087    def __init__(self, native: _NativeDs18b20Thermometer) -> None:
4088        """Wrap a native thermometer. Use :meth:`for_serial`, :meth:`at`, or
4089        :meth:`discover`."""
4090        self._native = native
4091
4092    @classmethod
4093    def for_serial(cls, serial: str) -> Ds18b20Thermometer:
4094        """Name a thermometer by the serial in its directory name.
4095
4096        :param serial: The twelve hex digits after ``28-``.
4097        :returns: The thermometer, reading ``/sys/bus/w1/devices/28-<serial>/w1_slave``.
4098        """
4099        return cls(_NativeDs18b20Thermometer.for_serial(serial))
4100
4101    @classmethod
4102    def at(cls, path: str) -> Ds18b20Thermometer:
4103        """Name a thermometer by the path of its ``w1_slave`` file.
4104
4105        :param path: The file to read.
4106        :returns: The thermometer.
4107        """
4108        return cls(_NativeDs18b20Thermometer.at(str(path)))
4109
4110    @classmethod
4111    def discover(cls, devices: Optional[str] = None) -> List[Ds18b20Thermometer]:
4112        """List every DS18B20 the kernel has found, one per ``28-`` directory.
4113
4114        :param devices: The directory the kernel lists its 1-Wire devices in, or ``None``
4115            for ``/sys/bus/w1/devices``.
4116        :returns: The thermometers, sorted by directory name.
4117        :raises PamojaError: If the directory cannot be listed, which usually means the
4118            1-Wire overlay is off.
4119        """
4120        found = _NativeDs18b20Thermometer.discover(None if devices is None else str(devices))
4121        return [cls(native) for native in found]
4122
4123    @property
4124    def path(self) -> str:
4125        """The path of the file the thermometer reads."""
4126        return self._native.path
4127
4128    @property
4129    def serial(self) -> Optional[str]:
4130        """The serial the kernel named the thermometer's directory after.
4131
4132        The twelve hex digits after ``28-``, which tell one probe from another and stay with
4133        the part for life, or ``None`` when the file does not sit in a DS18B20's directory, as
4134        one named by :meth:`at` may not.
4135
4136        >>> Ds18b20Thermometer.for_serial("000005e2fdc3").serial
4137        '000005e2fdc3'
4138        >>> Ds18b20Thermometer.at("/tmp/w1_slave").serial is None
4139        True
4140        """
4141        return self._native.serial
4142
4143    def read(self) -> Ds18b20Reading:
4144        """Read the file, which makes the kernel run a conversion, and decode it.
4145
4146        :returns: The checksum-checked reading.
4147        :raises PamojaError: If the file cannot be read, because the overlay is off, the
4148            probe is gone, or the process may not read it; or if the kernel or this decoder
4149            rejects the checksum.
4150        """
4151        return self._native.read()

A DS18B20 the Linux kernel serves as a w1_slave file.

On a Raspberry Pi the w1-gpio overlay (dtoverlay=w1-gpio in config.txt) puts a 1-Wire bus on GPIO 4, and the kernel lists every DS18B20 it finds under /sys/bus/w1/devices as a directory named by its family code and serial. Reading the directory's w1_slave file makes the kernel run a conversion and print the scratchpad, which read() decodes. The file is only text, so a test can write one anywhere and read it with at().

Ds18b20Thermometer(native: Ds18b20Thermometer)
4087    def __init__(self, native: _NativeDs18b20Thermometer) -> None:
4088        """Wrap a native thermometer. Use :meth:`for_serial`, :meth:`at`, or
4089        :meth:`discover`."""
4090        self._native = native

Wrap a native thermometer. Use for_serial(), at(), or discover().

@classmethod
def for_serial(cls, serial: str) -> Ds18b20Thermometer:
4092    @classmethod
4093    def for_serial(cls, serial: str) -> Ds18b20Thermometer:
4094        """Name a thermometer by the serial in its directory name.
4095
4096        :param serial: The twelve hex digits after ``28-``.
4097        :returns: The thermometer, reading ``/sys/bus/w1/devices/28-<serial>/w1_slave``.
4098        """
4099        return cls(_NativeDs18b20Thermometer.for_serial(serial))

Name a thermometer by the serial in its directory name.

Parameters
  • serial: The twelve hex digits after 28-. :returns: The thermometer, reading /sys/bus/w1/devices/28-<serial>/w1_slave.
@classmethod
def at(cls, path: str) -> Ds18b20Thermometer:
4101    @classmethod
4102    def at(cls, path: str) -> Ds18b20Thermometer:
4103        """Name a thermometer by the path of its ``w1_slave`` file.
4104
4105        :param path: The file to read.
4106        :returns: The thermometer.
4107        """
4108        return cls(_NativeDs18b20Thermometer.at(str(path)))

Name a thermometer by the path of its w1_slave file.

Parameters
  • path: The file to read. :returns: The thermometer.
@classmethod
def discover( cls, devices: Optional[str] = None) -> List[Ds18b20Thermometer]:
4110    @classmethod
4111    def discover(cls, devices: Optional[str] = None) -> List[Ds18b20Thermometer]:
4112        """List every DS18B20 the kernel has found, one per ``28-`` directory.
4113
4114        :param devices: The directory the kernel lists its 1-Wire devices in, or ``None``
4115            for ``/sys/bus/w1/devices``.
4116        :returns: The thermometers, sorted by directory name.
4117        :raises PamojaError: If the directory cannot be listed, which usually means the
4118            1-Wire overlay is off.
4119        """
4120        found = _NativeDs18b20Thermometer.discover(None if devices is None else str(devices))
4121        return [cls(native) for native in found]

List every DS18B20 the kernel has found, one per 28- directory.

Parameters
  • devices: The directory the kernel lists its 1-Wire devices in, or None for /sys/bus/w1/devices. :returns: The thermometers, sorted by directory name.
Raises
  • PamojaError: If the directory cannot be listed, which usually means the 1-Wire overlay is off.
path: str
4123    @property
4124    def path(self) -> str:
4125        """The path of the file the thermometer reads."""
4126        return self._native.path

The path of the file the thermometer reads.

serial: Optional[str]
4128    @property
4129    def serial(self) -> Optional[str]:
4130        """The serial the kernel named the thermometer's directory after.
4131
4132        The twelve hex digits after ``28-``, which tell one probe from another and stay with
4133        the part for life, or ``None`` when the file does not sit in a DS18B20's directory, as
4134        one named by :meth:`at` may not.
4135
4136        >>> Ds18b20Thermometer.for_serial("000005e2fdc3").serial
4137        '000005e2fdc3'
4138        >>> Ds18b20Thermometer.at("/tmp/w1_slave").serial is None
4139        True
4140        """
4141        return self._native.serial

The serial the kernel named the thermometer's directory after.

The twelve hex digits after 28-, which tell one probe from another and stay with the part for life, or None when the file does not sit in a DS18B20's directory, as one named by at() may not.

>>> Ds18b20Thermometer.for_serial("000005e2fdc3").serial
'000005e2fdc3'
>>> Ds18b20Thermometer.at("/tmp/w1_slave").serial is None
True
def read(self) -> Ds18b20Reading:
4143    def read(self) -> Ds18b20Reading:
4144        """Read the file, which makes the kernel run a conversion, and decode it.
4145
4146        :returns: The checksum-checked reading.
4147        :raises PamojaError: If the file cannot be read, because the overlay is off, the
4148            probe is gone, or the process may not read it; or if the kernel or this decoder
4149            rejects the checksum.
4150        """
4151        return self._native.read()

Read the file, which makes the kernel run a conversion, and decode it.

:returns: The checksum-checked reading.

Raises
  • PamojaError: If the file cannot be read, because the overlay is off, the probe is gone, or the process may not read it; or if the kernel or this decoder rejects the checksum.
class Hdc1080:
3622class Hdc1080:
3623    """A Texas Instruments HDC1080 driven over an :class:`~pamoja.hal.I2cBus`, measuring
3624    temperature then humidity from one trigger at its one address.
3625
3626    >>> from pamoja.hal import I2cBus
3627    >>> bus = I2cBus.simulated([hdc1080.sim.reporting(4.0, 91.0)])
3628    >>> round(Hdc1080(bus).measure().relative_humidity, 2)
3629    91.0
3630    """
3631
3632    __slots__ = ("_native",)
3633
3634    def __init__(
3635        self,
3636        bus: I2cBus,
3637        *,
3638        temperature_resolution: Hdc1080TemperatureResolution = (
3639            Hdc1080TemperatureResolution.BITS_14
3640        ),
3641        humidity_resolution: Hdc1080HumidityResolution = Hdc1080HumidityResolution.BITS_14,
3642    ) -> None:
3643        """Make a driver for the part on ``bus``.
3644
3645        :param bus: The bus the part is on.
3646        :param temperature_resolution: The temperature resolution, which sets its time.
3647        :param humidity_resolution: The humidity resolution, which sets its time.
3648        :raises ValueError: For a resolution the part does not have.
3649        """
3650        self._native = _NativeHdc1080(
3651            bus._native, int(temperature_resolution), int(humidity_resolution)
3652        )
3653
3654    def init(self) -> None:
3655        """Check the part is an HDC1080 and write the configuration.
3656
3657        :raises PamojaError: If nothing answers, or either id register is not an HDC1080's.
3658        """
3659        self._native.init()
3660
3661    def measure(self) -> Hdc1080Measurement:
3662        """Trigger one acquisition of both channels and read them, initializing the part
3663        first if :meth:`init` has not run.
3664
3665        :returns: The temperature and humidity.
3666        :raises PamojaError: As :meth:`init`, and when the part does not acknowledge the
3667            read, which it refuses until its results are ready.
3668        """
3669        return self._native.measure()
3670
3671    def heater(self, on: bool) -> None:
3672        """Switch the on-die heater, which runs only during acquisitions, on or off.
3673
3674        :param on: Whether the heater runs.
3675        :raises PamojaError: If the transfer fails.
3676        """
3677        self._native.heater(on)
3678
3679    @property
3680    def configuration(self) -> Hdc1080Config:
3681        """The configuration the driver writes."""
3682        return self._native.configuration

A Texas Instruments HDC1080 driven over an ~pamoja.hal.I2cBus, measuring temperature then humidity from one trigger at its one address.

>>> from pamoja.hal import I2cBus
>>> bus = I2cBus.simulated([hdc1080.sim.reporting(4.0, 91.0)])
>>> round(Hdc1080(bus).measure().relative_humidity, 2)
91.0
Hdc1080( bus: pamoja.hal.I2cBus, *, temperature_resolution: Hdc1080TemperatureResolution = <Hdc1080TemperatureResolution.BITS_14: 14>, humidity_resolution: Hdc1080HumidityResolution = <Hdc1080HumidityResolution.BITS_14: 14>)
3634    def __init__(
3635        self,
3636        bus: I2cBus,
3637        *,
3638        temperature_resolution: Hdc1080TemperatureResolution = (
3639            Hdc1080TemperatureResolution.BITS_14
3640        ),
3641        humidity_resolution: Hdc1080HumidityResolution = Hdc1080HumidityResolution.BITS_14,
3642    ) -> None:
3643        """Make a driver for the part on ``bus``.
3644
3645        :param bus: The bus the part is on.
3646        :param temperature_resolution: The temperature resolution, which sets its time.
3647        :param humidity_resolution: The humidity resolution, which sets its time.
3648        :raises ValueError: For a resolution the part does not have.
3649        """
3650        self._native = _NativeHdc1080(
3651            bus._native, int(temperature_resolution), int(humidity_resolution)
3652        )

Make a driver for the part on bus.

Parameters
  • bus: The bus the part is on.
  • temperature_resolution: The temperature resolution, which sets its time.
  • humidity_resolution: The humidity resolution, which sets its time.
Raises
  • ValueError: For a resolution the part does not have.
def init(self) -> None:
3654    def init(self) -> None:
3655        """Check the part is an HDC1080 and write the configuration.
3656
3657        :raises PamojaError: If nothing answers, or either id register is not an HDC1080's.
3658        """
3659        self._native.init()

Check the part is an HDC1080 and write the configuration.

Raises
  • PamojaError: If nothing answers, or either id register is not an HDC1080's.
def measure(self) -> Hdc1080Measurement:
3661    def measure(self) -> Hdc1080Measurement:
3662        """Trigger one acquisition of both channels and read them, initializing the part
3663        first if :meth:`init` has not run.
3664
3665        :returns: The temperature and humidity.
3666        :raises PamojaError: As :meth:`init`, and when the part does not acknowledge the
3667            read, which it refuses until its results are ready.
3668        """
3669        return self._native.measure()

Trigger one acquisition of both channels and read them, initializing the part first if init() has not run.

:returns: The temperature and humidity.

Raises
  • PamojaError: As init(), and when the part does not acknowledge the read, which it refuses until its results are ready.
def heater(self, on: bool) -> None:
3671    def heater(self, on: bool) -> None:
3672        """Switch the on-die heater, which runs only during acquisitions, on or off.
3673
3674        :param on: Whether the heater runs.
3675        :raises PamojaError: If the transfer fails.
3676        """
3677        self._native.heater(on)

Switch the on-die heater, which runs only during acquisitions, on or off.

Parameters
  • on: Whether the heater runs.
Raises
  • PamojaError: If the transfer fails.
configuration: Hdc1080Config
3679    @property
3680    def configuration(self) -> Hdc1080Config:
3681        """The configuration the driver writes."""
3682        return self._native.configuration

The configuration the driver writes.

class Hdc1080Config:

An HDC1080 configuration register, field by field.

battery_low

Whether the supply has dropped below 2.8 V, which the part reports back.

sequential

Whether one trigger acquires temperature and humidity in sequence.

software_reset

Whether writing this resets the part.

humidity_resolution_bits

The humidity resolution in bits: 14, 11, or 8.

heater

Whether the on-die heater runs during measurements.

temperature_resolution_bits

The temperature resolution in bits: 14 or 11.

class Hdc1080HumidityResolution(enum.IntEnum):
493class Hdc1080HumidityResolution(enum.IntEnum):
494    """An HDC1080 humidity resolution, as its bit count."""
495
496    #: 8 bits, 2.5 ms.
497    BITS_8 = 8
498    #: 11 bits, 3.85 ms.
499    BITS_11 = 11
500    #: 14 bits, 6.5 ms.
501    BITS_14 = 14

An HDC1080 humidity resolution, as its bit count.

class Hdc1080Measurement:

A decoded HDC1080 temperature and humidity pair.

milli_celsius

The temperature in milli-degrees Celsius, exact in integer arithmetic.

celsius

The temperature in degrees Celsius.

milli_percent

The relative humidity in milli-percent.

relative_humidity

The relative humidity as a percentage.

humidity_raw

The raw humidity register.

temperature_raw

The raw temperature register.

class Hdc1080TemperatureResolution(enum.IntEnum):
484class Hdc1080TemperatureResolution(enum.IntEnum):
485    """An HDC1080 temperature resolution, as its bit count."""
486
487    #: 11 bits, 3.65 ms.
488    BITS_11 = 11
489    #: 14 bits, 6.35 ms.
490    BITS_14 = 14

An HDC1080 temperature resolution, as its bit count.

class Ina219:
3685class Ina219:
3686    """A Texas Instruments INA219 driven over an :class:`~pamoja.hal.I2cBus`: shunt and bus
3687    voltage, current, and power on demand.
3688
3689    >>> from pamoja.hal import I2cBus
3690    >>> bus = I2cBus.simulated([ina219.sim.part(ina219.BASE_ADDRESS)])
3691    >>> Ina219(bus, ina219.BASE_ADDRESS).measure().bus_millivolts
3692    12000
3693    """
3694
3695    __slots__ = ("_native",)
3696
3697    def __init__(
3698        self,
3699        bus: I2cBus,
3700        address: int,
3701        *,
3702        shunt_milliohms: int = 100,
3703        max_microamps: int = 3_200_000,
3704        current_lsb_microamps: Optional[int] = None,
3705        config: Optional[Ina219Config] = None,
3706    ) -> None:
3707        """Make a driver for the part at ``address`` on ``bus``.
3708
3709        :param bus: The bus the part is on.
3710        :param address: ``ina219.BASE_ADDRESS`` plus what A1 and A0 add.
3711        :param shunt_milliohms: The shunt resistance; the common breakout's is 100.
3712        :param max_microamps: The largest current the shunt will carry, which sets the
3713            finest current step.
3714        :param current_lsb_microamps: A current step to use instead, such as a round 100.
3715        :param config: The range, gain, and converter settings; the power-on ones unless
3716            given.
3717        """
3718        self._native = _NativeIna219(
3719            bus._native,
3720            address,
3721            shunt_milliohms,
3722            max_microamps,
3723            current_lsb_microamps,
3724            config,
3725        )
3726
3727    def init(self) -> None:
3728        """Reset the part, write the configuration and the calibration, and read the
3729        calibration back, the identity check a part with no id register allows.
3730
3731        :raises PamojaError: If nothing answers, or the calibration does not hold.
3732        """
3733        self._native.init()
3734
3735    def measure(self) -> Ina219Reading:
3736        """Trigger one shunt and bus conversion and read every result, initializing the
3737        part first if :meth:`init` has not run.
3738
3739        :returns: The registers as read, and what they mean.
3740        :raises PamojaError: As :meth:`init`, and when the conversion-ready flag never sets.
3741        """
3742        return self._native.measure()
3743
3744    @property
3745    def current_lsb_microamps(self) -> int:
3746        """The current step the driver programs, in microamps per count."""
3747        return self._native.current_lsb_microamps
3748
3749    @property
3750    def calibration_word(self) -> int:
3751        """The calibration word the driver programs."""
3752        return self._native.calibration_word

A Texas Instruments INA219 driven over an ~pamoja.hal.I2cBus: shunt and bus voltage, current, and power on demand.

>>> from pamoja.hal import I2cBus
>>> bus = I2cBus.simulated([ina219.sim.part(ina219.BASE_ADDRESS)])
>>> Ina219(bus, ina219.BASE_ADDRESS).measure().bus_millivolts
12000
Ina219( bus: pamoja.hal.I2cBus, address: int, *, shunt_milliohms: int = 100, max_microamps: int = 3200000, current_lsb_microamps: Optional[int] = None, config: Optional[Ina219Config] = None)
3697    def __init__(
3698        self,
3699        bus: I2cBus,
3700        address: int,
3701        *,
3702        shunt_milliohms: int = 100,
3703        max_microamps: int = 3_200_000,
3704        current_lsb_microamps: Optional[int] = None,
3705        config: Optional[Ina219Config] = None,
3706    ) -> None:
3707        """Make a driver for the part at ``address`` on ``bus``.
3708
3709        :param bus: The bus the part is on.
3710        :param address: ``ina219.BASE_ADDRESS`` plus what A1 and A0 add.
3711        :param shunt_milliohms: The shunt resistance; the common breakout's is 100.
3712        :param max_microamps: The largest current the shunt will carry, which sets the
3713            finest current step.
3714        :param current_lsb_microamps: A current step to use instead, such as a round 100.
3715        :param config: The range, gain, and converter settings; the power-on ones unless
3716            given.
3717        """
3718        self._native = _NativeIna219(
3719            bus._native,
3720            address,
3721            shunt_milliohms,
3722            max_microamps,
3723            current_lsb_microamps,
3724            config,
3725        )

Make a driver for the part at address on bus.

Parameters
  • bus: The bus the part is on.
  • address: ina219.BASE_ADDRESS plus what A1 and A0 add.
  • shunt_milliohms: The shunt resistance; the common breakout's is 100.
  • max_microamps: The largest current the shunt will carry, which sets the finest current step.
  • current_lsb_microamps: A current step to use instead, such as a round 100.
  • config: The range, gain, and converter settings; the power-on ones unless given.
def init(self) -> None:
3727    def init(self) -> None:
3728        """Reset the part, write the configuration and the calibration, and read the
3729        calibration back, the identity check a part with no id register allows.
3730
3731        :raises PamojaError: If nothing answers, or the calibration does not hold.
3732        """
3733        self._native.init()

Reset the part, write the configuration and the calibration, and read the calibration back, the identity check a part with no id register allows.

Raises
  • PamojaError: If nothing answers, or the calibration does not hold.
def measure(self) -> Ina219Reading:
3735    def measure(self) -> Ina219Reading:
3736        """Trigger one shunt and bus conversion and read every result, initializing the
3737        part first if :meth:`init` has not run.
3738
3739        :returns: The registers as read, and what they mean.
3740        :raises PamojaError: As :meth:`init`, and when the conversion-ready flag never sets.
3741        """
3742        return self._native.measure()

Trigger one shunt and bus conversion and read every result, initializing the part first if init() has not run.

:returns: The registers as read, and what they mean.

Raises
  • PamojaError: As init(), and when the conversion-ready flag never sets.
current_lsb_microamps: int
3744    @property
3745    def current_lsb_microamps(self) -> int:
3746        """The current step the driver programs, in microamps per count."""
3747        return self._native.current_lsb_microamps

The current step the driver programs, in microamps per count.

calibration_word: int
3749    @property
3750    def calibration_word(self) -> int:
3751        """The calibration word the driver programs."""
3752        return self._native.calibration_word

The calibration word the driver programs.

class Ina219Adc(enum.IntEnum):
526class Ina219Adc(enum.IntEnum):
527    """An INA219 converter setting: a resolution, or samples averaged at 12 bits."""
528
529    #: 9 bits, 84 us.
530    BITS_9 = 0b0000
531    #: 10 bits, 148 us.
532    BITS_10 = 0b0001
533    #: 11 bits, 276 us.
534    BITS_11 = 0b0010
535    #: 12 bits, 532 us, the reset setting.
536    BITS_12 = 0b0011
537    #: 2 samples averaged, 1.06 ms.
538    SAMPLES_2 = 0b1001
539    #: 4 samples averaged, 2.13 ms.
540    SAMPLES_4 = 0b1010
541    #: 8 samples averaged, 4.26 ms.
542    SAMPLES_8 = 0b1011
543    #: 16 samples averaged, 8.51 ms.
544    SAMPLES_16 = 0b1100
545    #: 32 samples averaged, 17.02 ms.
546    SAMPLES_32 = 0b1101
547    #: 64 samples averaged, 34.05 ms.
548    SAMPLES_64 = 0b1110
549    #: 128 samples averaged, 68.10 ms.
550    SAMPLES_128 = 0b1111

An INA219 converter setting: a resolution, or samples averaged at 12 bits.

BITS_9 = <Ina219Adc.BITS_9: 0>
BITS_10 = <Ina219Adc.BITS_10: 1>
BITS_11 = <Ina219Adc.BITS_11: 2>
BITS_12 = <Ina219Adc.BITS_12: 3>
SAMPLES_2 = <Ina219Adc.SAMPLES_2: 9>
SAMPLES_4 = <Ina219Adc.SAMPLES_4: 10>
SAMPLES_8 = <Ina219Adc.SAMPLES_8: 11>
SAMPLES_16 = <Ina219Adc.SAMPLES_16: 12>
SAMPLES_32 = <Ina219Adc.SAMPLES_32: 13>
SAMPLES_64 = <Ina219Adc.SAMPLES_64: 14>
SAMPLES_128 = <Ina219Adc.SAMPLES_128: 15>
class Ina219BusRange(enum.IntEnum):
504class Ina219BusRange(enum.IntEnum):
505    """An INA219 bus-voltage range, as its register code."""
506
507    #: 0 to 16 V.
508    V16 = 0
509    #: 0 to 32 V, the reset setting.
510    V32 = 1

An INA219 bus-voltage range, as its register code.

V16 = <Ina219BusRange.V16: 0>
V32 = <Ina219BusRange.V32: 1>
class Ina219Config:

An INA219 configuration register, field by field, each setting as the code the datasheet prints.

reset

Whether writing this resets the part.

bus_range

The bus-voltage range code: 0 for 16 V, 1 for 32 V.

shunt_adc

The shunt converter code, as bus_adc.

gain

The shunt gain code, 0..=3, for ranges of 40, 80, 160, and 320 mV.

bus_adc

The bus converter code, 0..=15: a resolution below 8, a sample count averaged at 12 bits from 9 up.

mode

The operating-mode code, 0..=7.

class Ina219Gain(enum.IntEnum):
513class Ina219Gain(enum.IntEnum):
514    """An INA219 shunt gain, by the shunt-voltage range it gives, as its register code."""
515
516    #: Gain 1, 40 mV either side of zero.
517    DIV1 = 0
518    #: Gain 1/2, 80 mV.
519    DIV2 = 1
520    #: Gain 1/4, 160 mV.
521    DIV4 = 2
522    #: Gain 1/8, 320 mV, the reset setting.
523    DIV8 = 3

An INA219 shunt gain, by the shunt-voltage range it gives, as its register code.

DIV1 = <Ina219Gain.DIV1: 0>
DIV2 = <Ina219Gain.DIV2: 1>
DIV4 = <Ina219Gain.DIV4: 2>
DIV8 = <Ina219Gain.DIV8: 3>
class Ina219Mode(enum.IntEnum):
553class Ina219Mode(enum.IntEnum):
554    """An INA219 operating mode, as its register code."""
555
556    #: No conversions, lowest power.
557    POWER_DOWN = 0
558    #: One shunt conversion.
559    SHUNT_TRIGGERED = 1
560    #: One bus conversion.
561    BUS_TRIGGERED = 2
562    #: One shunt and one bus conversion.
563    SHUNT_AND_BUS_TRIGGERED = 3
564    #: The converter disabled.
565    ADC_OFF = 4
566    #: Shunt conversions back to back.
567    SHUNT_CONTINUOUS = 5
568    #: Bus conversions back to back.
569    BUS_CONTINUOUS = 6
570    #: Shunt and bus conversions back to back, the reset setting.
571    SHUNT_AND_BUS_CONTINUOUS = 7

An INA219 operating mode, as its register code.

POWER_DOWN = <Ina219Mode.POWER_DOWN: 0>
SHUNT_TRIGGERED = <Ina219Mode.SHUNT_TRIGGERED: 1>
BUS_TRIGGERED = <Ina219Mode.BUS_TRIGGERED: 2>
SHUNT_AND_BUS_TRIGGERED = <Ina219Mode.SHUNT_AND_BUS_TRIGGERED: 3>
ADC_OFF = <Ina219Mode.ADC_OFF: 4>
SHUNT_CONTINUOUS = <Ina219Mode.SHUNT_CONTINUOUS: 5>
BUS_CONTINUOUS = <Ina219Mode.BUS_CONTINUOUS: 6>
SHUNT_AND_BUS_CONTINUOUS = <Ina219Mode.SHUNT_AND_BUS_CONTINUOUS: 7>
class Ina219Reading:

One INA219 conversion: the four result registers as read, and what they mean.

power_microwatts

The power in microwatts.

current

The current register.

shunt_microvolts

The shunt voltage in microvolts.

current_microamps

The current in microamps; negative flows the other way through the shunt.

math_overflow

Whether the part's arithmetic overflowed, leaving current and power meaningless.

current_lsb_microamps

The current step the calibration programmed, in microamps per count.

bus

The bus-voltage register, flags included.

power

The power register.

bus_millivolts

The bus voltage in millivolts.

shunt

The shunt-voltage register.

class Ina226:
3755class Ina226:
3756    """A Texas Instruments INA226 driven over an :class:`~pamoja.hal.I2cBus`: shunt and bus
3757    voltage, current, and power on demand.
3758
3759    >>> from pamoja.hal import I2cBus
3760    >>> bus = I2cBus.simulated([ina226.sim.part(ina226.BASE_ADDRESS)])
3761    >>> Ina226(bus, ina226.BASE_ADDRESS).measure().bus_microvolts
3762    12000000
3763    """
3764
3765    __slots__ = ("_native",)
3766
3767    def __init__(
3768        self,
3769        bus: I2cBus,
3770        address: int,
3771        *,
3772        shunt_milliohms: int = 100,
3773        max_microamps: int = 3_200_000,
3774        current_lsb_microamps: Optional[int] = None,
3775        config: Optional[Ina226Config] = None,
3776    ) -> None:
3777        """Make a driver for the part at ``address`` on ``bus``.
3778
3779        :param bus: The bus the part is on.
3780        :param address: The address A1 and A0 select, which ``ina226.address`` works out.
3781        :param shunt_milliohms: The shunt resistance.
3782        :param max_microamps: The largest current the shunt will carry, which sets the
3783            finest current step.
3784        :param current_lsb_microamps: A current step to use instead.
3785        :param config: The averaging and conversion times; the power-on ones unless given.
3786        """
3787        self._native = _NativeIna226(
3788            bus._native,
3789            address,
3790            shunt_milliohms,
3791            max_microamps,
3792            current_lsb_microamps,
3793            config,
3794        )
3795
3796    def init(self) -> None:
3797        """Reset the part, check it is an INA226, and program the configuration and
3798        calibration.
3799
3800        :raises PamojaError: If nothing answers, the id registers are not an INA226's, or
3801            the calibration does not read back.
3802        """
3803        self._native.init()
3804
3805    def measure(self) -> Ina226Reading:
3806        """Trigger one shunt and bus conversion and read every result, initializing the
3807        part first if :meth:`init` has not run.
3808
3809        :returns: The registers as read, and what they mean.
3810        :raises PamojaError: As :meth:`init`, and when the conversion-ready flag never sets.
3811        """
3812        return self._native.measure()
3813
3814    def set_alert(self, mask: Ina226MaskEnable, limit: int) -> None:
3815        """Program the alert pin: which limit it watches, and the limit.
3816
3817        :param mask: The mask/enable settings, one alert function at a time.
3818        :param limit: The alert-limit register, in the units of the register the function
3819            watches.
3820        :raises PamojaError: If the transfer fails.
3821        """
3822        self._native.set_alert(mask, limit)
3823
3824    @property
3825    def current_lsb_microamps(self) -> int:
3826        """The current step the driver programs, in microamps per count."""
3827        return self._native.current_lsb_microamps
3828
3829    @property
3830    def calibration_word(self) -> int:
3831        """The calibration word the driver programs."""
3832        return self._native.calibration_word
3833
3834    @property
3835    def identity(self) -> Optional[Ina226DieId]:
3836        """The die id read at initialization, or ``None`` before it."""
3837        return self._native.identity

A Texas Instruments INA226 driven over an ~pamoja.hal.I2cBus: shunt and bus voltage, current, and power on demand.

>>> from pamoja.hal import I2cBus
>>> bus = I2cBus.simulated([ina226.sim.part(ina226.BASE_ADDRESS)])
>>> Ina226(bus, ina226.BASE_ADDRESS).measure().bus_microvolts
12000000
Ina226( bus: pamoja.hal.I2cBus, address: int, *, shunt_milliohms: int = 100, max_microamps: int = 3200000, current_lsb_microamps: Optional[int] = None, config: Optional[Ina226Config] = None)
3767    def __init__(
3768        self,
3769        bus: I2cBus,
3770        address: int,
3771        *,
3772        shunt_milliohms: int = 100,
3773        max_microamps: int = 3_200_000,
3774        current_lsb_microamps: Optional[int] = None,
3775        config: Optional[Ina226Config] = None,
3776    ) -> None:
3777        """Make a driver for the part at ``address`` on ``bus``.
3778
3779        :param bus: The bus the part is on.
3780        :param address: The address A1 and A0 select, which ``ina226.address`` works out.
3781        :param shunt_milliohms: The shunt resistance.
3782        :param max_microamps: The largest current the shunt will carry, which sets the
3783            finest current step.
3784        :param current_lsb_microamps: A current step to use instead.
3785        :param config: The averaging and conversion times; the power-on ones unless given.
3786        """
3787        self._native = _NativeIna226(
3788            bus._native,
3789            address,
3790            shunt_milliohms,
3791            max_microamps,
3792            current_lsb_microamps,
3793            config,
3794        )

Make a driver for the part at address on bus.

Parameters
  • bus: The bus the part is on.
  • address: The address A1 and A0 select, which ina226.address works out.
  • shunt_milliohms: The shunt resistance.
  • max_microamps: The largest current the shunt will carry, which sets the finest current step.
  • current_lsb_microamps: A current step to use instead.
  • config: The averaging and conversion times; the power-on ones unless given.
def init(self) -> None:
3796    def init(self) -> None:
3797        """Reset the part, check it is an INA226, and program the configuration and
3798        calibration.
3799
3800        :raises PamojaError: If nothing answers, the id registers are not an INA226's, or
3801            the calibration does not read back.
3802        """
3803        self._native.init()

Reset the part, check it is an INA226, and program the configuration and calibration.

Raises
  • PamojaError: If nothing answers, the id registers are not an INA226's, or the calibration does not read back.
def measure(self) -> Ina226Reading:
3805    def measure(self) -> Ina226Reading:
3806        """Trigger one shunt and bus conversion and read every result, initializing the
3807        part first if :meth:`init` has not run.
3808
3809        :returns: The registers as read, and what they mean.
3810        :raises PamojaError: As :meth:`init`, and when the conversion-ready flag never sets.
3811        """
3812        return self._native.measure()

Trigger one shunt and bus conversion and read every result, initializing the part first if init() has not run.

:returns: The registers as read, and what they mean.

Raises
  • PamojaError: As init(), and when the conversion-ready flag never sets.
def set_alert(self, mask: Ina226MaskEnable, limit: int) -> None:
3814    def set_alert(self, mask: Ina226MaskEnable, limit: int) -> None:
3815        """Program the alert pin: which limit it watches, and the limit.
3816
3817        :param mask: The mask/enable settings, one alert function at a time.
3818        :param limit: The alert-limit register, in the units of the register the function
3819            watches.
3820        :raises PamojaError: If the transfer fails.
3821        """
3822        self._native.set_alert(mask, limit)

Program the alert pin: which limit it watches, and the limit.

Parameters
  • mask: The mask/enable settings, one alert function at a time.
  • limit: The alert-limit register, in the units of the register the function watches.
Raises
  • PamojaError: If the transfer fails.
current_lsb_microamps: int
3824    @property
3825    def current_lsb_microamps(self) -> int:
3826        """The current step the driver programs, in microamps per count."""
3827        return self._native.current_lsb_microamps

The current step the driver programs, in microamps per count.

calibration_word: int
3829    @property
3830    def calibration_word(self) -> int:
3831        """The calibration word the driver programs."""
3832        return self._native.calibration_word

The calibration word the driver programs.

identity: Optional[Ina226DieId]
3834    @property
3835    def identity(self) -> Optional[Ina226DieId]:
3836        """The die id read at initialization, or ``None`` before it."""
3837        return self._native.identity

The die id read at initialization, or None before it.

class Ina226AlertFunction(builtins.str, enum.Enum):
1516class Ina226AlertFunction(str, enum.Enum):
1517    """The limit comparison an INA226 alert pin responds to."""
1518
1519    #: The shunt voltage rose above the alert limit.
1520    SHUNT_OVER_LIMIT = "ShuntOverLimit"
1521    #: The shunt voltage fell below the alert limit.
1522    SHUNT_UNDER_LIMIT = "ShuntUnderLimit"
1523    #: The bus voltage rose above the alert limit.
1524    BUS_OVER_LIMIT = "BusOverLimit"
1525    #: The bus voltage fell below the alert limit.
1526    BUS_UNDER_LIMIT = "BusUnderLimit"
1527    #: The power rose above the alert limit.
1528    POWER_OVER_LIMIT = "PowerOverLimit"

The limit comparison an INA226 alert pin responds to.

SHUNT_OVER_LIMIT = <Ina226AlertFunction.SHUNT_OVER_LIMIT: 'ShuntOverLimit'>
SHUNT_UNDER_LIMIT = <Ina226AlertFunction.SHUNT_UNDER_LIMIT: 'ShuntUnderLimit'>
BUS_OVER_LIMIT = <Ina226AlertFunction.BUS_OVER_LIMIT: 'BusOverLimit'>
BUS_UNDER_LIMIT = <Ina226AlertFunction.BUS_UNDER_LIMIT: 'BusUnderLimit'>
POWER_OVER_LIMIT = <Ina226AlertFunction.POWER_OVER_LIMIT: 'PowerOverLimit'>
class Ina226Averaging(enum.IntEnum):
574class Ina226Averaging(enum.IntEnum):
575    """How many samples an INA226 folds into each result, as its register code."""
576
577    #: Every conversion reported, the reset setting.
578    SAMPLES_1 = 0
579    #: 4 samples.
580    SAMPLES_4 = 1
581    #: 16 samples.
582    SAMPLES_16 = 2
583    #: 64 samples.
584    SAMPLES_64 = 3
585    #: 128 samples.
586    SAMPLES_128 = 4
587    #: 256 samples.
588    SAMPLES_256 = 5
589    #: 512 samples.
590    SAMPLES_512 = 6
591    #: 1024 samples.
592    SAMPLES_1024 = 7

How many samples an INA226 folds into each result, as its register code.

SAMPLES_1 = <Ina226Averaging.SAMPLES_1: 0>
SAMPLES_4 = <Ina226Averaging.SAMPLES_4: 1>
SAMPLES_16 = <Ina226Averaging.SAMPLES_16: 2>
SAMPLES_64 = <Ina226Averaging.SAMPLES_64: 3>
SAMPLES_128 = <Ina226Averaging.SAMPLES_128: 4>
SAMPLES_256 = <Ina226Averaging.SAMPLES_256: 5>
SAMPLES_512 = <Ina226Averaging.SAMPLES_512: 6>
SAMPLES_1024 = <Ina226Averaging.SAMPLES_1024: 7>
class Ina226Config:

An INA226 configuration register, field by field.

shunt_conversion_time

The shunt-voltage conversion-time code, 0..=7.

mode

The operating-mode code, 0..=7.

averaging

The averaging code, 0..=7, from 1 to 1024 samples.

reset

Whether writing this resets the part.

bus_conversion_time

The bus-voltage conversion-time code, 0..=7.

class Ina226ConversionTime(enum.IntEnum):
595class Ina226ConversionTime(enum.IntEnum):
596    """An INA226 conversion time, for the bus or the shunt voltage, as its register code."""
597
598    #: 140 us.
599    US_140 = 0
600    #: 204 us.
601    US_204 = 1
602    #: 332 us.
603    US_332 = 2
604    #: 588 us.
605    US_588 = 3
606    #: 1.1 ms, the reset setting.
607    US_1100 = 4
608    #: 2.116 ms.
609    US_2116 = 5
610    #: 4.156 ms.
611    US_4156 = 6
612    #: 8.244 ms.
613    US_8244 = 7

An INA226 conversion time, for the bus or the shunt voltage, as its register code.

class Ina226DieId:

A decoded INA226 die-ID register.

device

The 12-bit device identifier.

revision

The 4-bit die revision.

class Ina226Mode(enum.IntEnum):
616class Ina226Mode(enum.IntEnum):
617    """An INA226 operating mode, as its register code."""
618
619    #: No conversions; the registers stay readable and writable.
620    POWER_DOWN = 0
621    #: One shunt conversion.
622    SHUNT_TRIGGERED = 1
623    #: One bus conversion.
624    BUS_TRIGGERED = 2
625    #: One shunt and one bus conversion.
626    SHUNT_AND_BUS_TRIGGERED = 3
627    #: Shunt conversions back to back.
628    SHUNT_CONTINUOUS = 5
629    #: Bus conversions back to back.
630    BUS_CONTINUOUS = 6
631    #: Shunt and bus conversions back to back, the reset setting.
632    SHUNT_AND_BUS_CONTINUOUS = 7

An INA226 operating mode, as its register code.

POWER_DOWN = <Ina226Mode.POWER_DOWN: 0>
SHUNT_TRIGGERED = <Ina226Mode.SHUNT_TRIGGERED: 1>
BUS_TRIGGERED = <Ina226Mode.BUS_TRIGGERED: 2>
SHUNT_AND_BUS_TRIGGERED = <Ina226Mode.SHUNT_AND_BUS_TRIGGERED: 3>
SHUNT_CONTINUOUS = <Ina226Mode.SHUNT_CONTINUOUS: 5>
BUS_CONTINUOUS = <Ina226Mode.BUS_CONTINUOUS: 6>
SHUNT_AND_BUS_CONTINUOUS = <Ina226Mode.SHUNT_AND_BUS_CONTINUOUS: 7>
class Ina226MaskEnable:

An INA226 Mask/Enable register, field by field.

bus_over_limit

Alert when the bus voltage exceeds the limit.

power_over_limit

Alert when the power exceeds the limit.

alert_function_flag

Whether the selected limit function caused the last alert.

shunt_under_limit

Alert when the shunt voltage drops below the limit.

bus_under_limit

Alert when the bus voltage drops below the limit.

math_overflow

Whether an arithmetic overflow left current and power invalid.

alert_active_high

Whether the alert pin is active high.

alert_latch

Whether the alert pin latches until this register is read.

conversion_ready

Also alert when a conversion completes.

conversion_ready_flag

Whether every conversion and multiplication has completed.

shunt_over_limit

Alert when the shunt voltage exceeds the limit.

class Ina226Reading:

One INA226 conversion: the four result registers as read, and what they mean.

bus

The bus-voltage register.

bus_microvolts

The bus voltage in microvolts.

shunt

The shunt-voltage register.

power

The power register.

bus_volts

The bus voltage in volts.

current_microamps

The current in microamps; negative flows the other way through the shunt.

current_lsb_microamps

The current step the calibration programmed, in microamps per count.

shunt_nanovolts

The shunt voltage in nanovolts.

current

The current register.

power_microwatts

The power in microwatts.

power_watts

The power in watts.

shunt_millivolts

The shunt voltage in millivolts.

current_amps

The current in amps.

math_overflow

Whether the part's arithmetic overflowed, leaving current and power meaningless.

class Opt3001:
3555class Opt3001:
3556    """A Texas Instruments OPT3001 driven over an :class:`~pamoja.hal.I2cBus`, measuring
3557    illuminance on demand in single-shot mode.
3558
3559    >>> from pamoja.hal import I2cBus
3560    >>> bus = I2cBus.simulated([opt3001.sim.reporting(opt3001.ADDRESS_GND, 1200.0)])
3561    >>> Opt3001(bus, opt3001.ADDRESS_GND).measure().lux
3562    1200.0
3563    """
3564
3565    __slots__ = ("_native",)
3566
3567    def __init__(
3568        self,
3569        bus: I2cBus,
3570        address: int,
3571        *,
3572        conversion_time: Opt3001ConversionTime = Opt3001ConversionTime.MS_800,
3573        range_number: int = 12,
3574    ) -> None:
3575        """Make a driver for the part at ``address`` on ``bus``.
3576
3577        :param bus: The bus the part is on.
3578        :param address: One of the ``opt3001.ADDRESS_*`` constants, by where ADDR is tied.
3579        :param conversion_time: How long each conversion integrates.
3580        :param range_number: A fixed full-scale range, ``0`` to ``11``, or ``12`` to let
3581            the part choose.
3582        """
3583        self._native = _NativeOpt3001(
3584            bus._native,
3585            address,
3586            Opt3001ConversionTime(conversion_time) == Opt3001ConversionTime.MS_800,
3587            range_number,
3588        )
3589
3590    def init(self) -> None:
3591        """Check the part is an OPT3001 and write the settings with the part in shutdown.
3592
3593        :raises PamojaError: If nothing answers, or either id register is not an OPT3001's.
3594        """
3595        self._native.init()
3596
3597    def measure(self) -> Opt3001Reading:
3598        """Run one conversion and read the illuminance, initializing the part first if
3599        :meth:`init` has not run.
3600
3601        :returns: The illuminance.
3602        :raises PamojaError: As :meth:`init`, and when the conversion never finishes.
3603        """
3604        return self._native.measure()
3605
3606    def set_limits(self, low_milli_lux: int, high_milli_lux: int) -> None:
3607        """Write the low and high limits the part's interrupt pin compares each result
3608        against.
3609
3610        :param low_milli_lux: The low limit, in millilux.
3611        :param high_milli_lux: The high limit, in millilux.
3612        :raises PamojaError: If the transfer fails.
3613        """
3614        self._native.set_limits(low_milli_lux, high_milli_lux)
3615
3616    @property
3617    def configuration(self) -> Opt3001Config:
3618        """The configuration the driver writes, with the part in shutdown."""
3619        return self._native.configuration

A Texas Instruments OPT3001 driven over an ~pamoja.hal.I2cBus, measuring illuminance on demand in single-shot mode.

>>> from pamoja.hal import I2cBus
>>> bus = I2cBus.simulated([opt3001.sim.reporting(opt3001.ADDRESS_GND, 1200.0)])
>>> Opt3001(bus, opt3001.ADDRESS_GND).measure().lux
1200.0
Opt3001( bus: pamoja.hal.I2cBus, address: int, *, conversion_time: Opt3001ConversionTime = <Opt3001ConversionTime.MS_800: 800>, range_number: int = 12)
3567    def __init__(
3568        self,
3569        bus: I2cBus,
3570        address: int,
3571        *,
3572        conversion_time: Opt3001ConversionTime = Opt3001ConversionTime.MS_800,
3573        range_number: int = 12,
3574    ) -> None:
3575        """Make a driver for the part at ``address`` on ``bus``.
3576
3577        :param bus: The bus the part is on.
3578        :param address: One of the ``opt3001.ADDRESS_*`` constants, by where ADDR is tied.
3579        :param conversion_time: How long each conversion integrates.
3580        :param range_number: A fixed full-scale range, ``0`` to ``11``, or ``12`` to let
3581            the part choose.
3582        """
3583        self._native = _NativeOpt3001(
3584            bus._native,
3585            address,
3586            Opt3001ConversionTime(conversion_time) == Opt3001ConversionTime.MS_800,
3587            range_number,
3588        )

Make a driver for the part at address on bus.

Parameters
  • bus: The bus the part is on.
  • address: One of the opt3001.ADDRESS_* constants, by where ADDR is tied.
  • conversion_time: How long each conversion integrates.
  • range_number: A fixed full-scale range, 0 to 11, or 12 to let the part choose.
def init(self) -> None:
3590    def init(self) -> None:
3591        """Check the part is an OPT3001 and write the settings with the part in shutdown.
3592
3593        :raises PamojaError: If nothing answers, or either id register is not an OPT3001's.
3594        """
3595        self._native.init()

Check the part is an OPT3001 and write the settings with the part in shutdown.

Raises
  • PamojaError: If nothing answers, or either id register is not an OPT3001's.
def measure(self) -> Opt3001Reading:
3597    def measure(self) -> Opt3001Reading:
3598        """Run one conversion and read the illuminance, initializing the part first if
3599        :meth:`init` has not run.
3600
3601        :returns: The illuminance.
3602        :raises PamojaError: As :meth:`init`, and when the conversion never finishes.
3603        """
3604        return self._native.measure()

Run one conversion and read the illuminance, initializing the part first if init() has not run.

:returns: The illuminance.

Raises
  • PamojaError: As init(), and when the conversion never finishes.
def set_limits(self, low_milli_lux: int, high_milli_lux: int) -> None:
3606    def set_limits(self, low_milli_lux: int, high_milli_lux: int) -> None:
3607        """Write the low and high limits the part's interrupt pin compares each result
3608        against.
3609
3610        :param low_milli_lux: The low limit, in millilux.
3611        :param high_milli_lux: The high limit, in millilux.
3612        :raises PamojaError: If the transfer fails.
3613        """
3614        self._native.set_limits(low_milli_lux, high_milli_lux)

Write the low and high limits the part's interrupt pin compares each result against.

Parameters
  • low_milli_lux: The low limit, in millilux.
  • high_milli_lux: The high limit, in millilux.
Raises
  • PamojaError: If the transfer fails.
configuration: Opt3001Config
3616    @property
3617    def configuration(self) -> Opt3001Config:
3618        """The configuration the driver writes, with the part in shutdown."""
3619        return self._native.configuration

The configuration the driver writes, with the part in shutdown.

class Opt3001Config:

An OPT3001 configuration register, field by field.

overflow

Whether the last result overflowed its range.

latched_window

Whether the INT pin latches until the configuration register is read.

mask_exponent

Whether the limit registers carry a mantissa alone, without an exponent.

active_high

Whether the INT pin is active high.

long_conversion

Whether a conversion takes 800 ms rather than 100 ms.

fault_count

The fault-count code, 0..=3, for one, two, four, or eight faults.

conversion_ready

Whether a conversion has completed since the register was last read.

range_number

The full-scale range number, 0..=11, or 12 to set the range automatically.

mode

The mode code: 0 shutdown, 1 single shot, 2 continuous.

flag_high

Whether the result went above the high limit.

flag_low

Whether the result went below the low limit.

class Opt3001ConversionTime(enum.IntEnum):
475class Opt3001ConversionTime(enum.IntEnum):
476    """How long an OPT3001 conversion integrates, in milliseconds."""
477
478    #: 100 ms, for speed.
479    MS_100 = 100
480    #: 800 ms, for resolution; the part's reset setting.
481    MS_800 = 800

How long an OPT3001 conversion integrates, in milliseconds.

class Opt3001Reading:

An OPT3001 illuminance result.

lux

The illuminance in lux.

raw

The result register: a four-bit exponent over a twelve-bit mantissa.

milli_lux

The illuminance in millilux, exact in integer arithmetic.

class Scd4x:
3982class Scd4x:
3983    """A Sensirion SCD40 or SCD41 driven over an :class:`~pamoja.hal.I2cBus` in periodic
3984    measurement, a result every five seconds.
3985
3986    >>> from pamoja.hal import I2cBus
3987    >>> bus = I2cBus.simulated([scd4x.sim.reporting(1450, 24.0, 55.0)])
3988    >>> Scd4x(bus).measure().co2_ppm
3989    1450
3990    """
3991
3992    __slots__ = ("_native",)
3993
3994    def __init__(self, bus: I2cBus) -> None:
3995        """Make a driver for the part on ``bus``, which has one address.
3996
3997        :param bus: The bus the part is on.
3998        """
3999        self._native = _NativeScd4x(bus._native)
4000
4001    def init(self) -> None:
4002        """Stop any running measurement, read the serial number, and start periodic
4003        measurement.
4004
4005        :raises PamojaError: If nothing answers, or the serial number fails its checksum.
4006        """
4007        self._native.init()
4008
4009    def measure(self) -> Scd4xMeasurement:
4010        """Wait for the next periodic result and read it, initializing the part first if
4011        :meth:`init` has not run.
4012
4013        :returns: The carbon dioxide, temperature, and humidity.
4014        :raises PamojaError: As :meth:`init`, when no result becomes ready, and when a word
4015            fails its checksum.
4016        """
4017        return self._native.measure()
4018
4019    def measure_single_shot(self) -> Scd4xMeasurement:
4020        """Run one on-demand measurement on an SCD41, which takes five seconds. The part
4021        must not be measuring periodically: call :meth:`stop` first, or use this in place
4022        of :meth:`init`.
4023
4024        :returns: The measurement.
4025        :raises PamojaError: As :meth:`measure`.
4026        """
4027        return self._native.measure_single_shot()
4028
4029    def data_ready(self) -> bool:
4030        """Ask the part whether a periodic result is waiting.
4031
4032        :returns: Whether :meth:`measure` would read without waiting.
4033        :raises PamojaError: If the transfer fails or the word fails its checksum.
4034        """
4035        return self._native.data_ready()
4036
4037    def stop(self) -> None:
4038        """Stop periodic measurement, after which the part takes its settings commands.
4039
4040        :raises PamojaError: If the transfer fails.
4041        """
4042        self._native.stop()
4043
4044    def start(self) -> None:
4045        """Start periodic measurement.
4046
4047        :raises PamojaError: If the transfer fails.
4048        """
4049        self._native.start()
4050
4051    def set_temperature_offset(self, milli_celsius: int) -> None:
4052        """Set the temperature offset that compensates the part's own warmth, until power
4053        is lost.
4054
4055        :param milli_celsius: The offset to subtract, in millidegrees.
4056        :raises PamojaError: If the transfer fails.
4057        """
4058        self._native.set_temperature_offset(milli_celsius)
4059
4060    def set_sensor_altitude(self, meters: int) -> None:
4061        """Set the altitude the part corrects its carbon dioxide reading for.
4062
4063        :param meters: The altitude above sea level.
4064        :raises PamojaError: If the transfer fails.
4065        """
4066        self._native.set_sensor_altitude(meters)
4067
4068    @property
4069    def serial(self) -> Optional[int]:
4070        """The 48-bit serial number read at initialization, or ``None`` before it."""
4071        return self._native.serial

A Sensirion SCD40 or SCD41 driven over an ~pamoja.hal.I2cBus in periodic measurement, a result every five seconds.

>>> from pamoja.hal import I2cBus
>>> bus = I2cBus.simulated([scd4x.sim.reporting(1450, 24.0, 55.0)])
>>> Scd4x(bus).measure().co2_ppm
1450
Scd4x(bus: pamoja.hal.I2cBus)
3994    def __init__(self, bus: I2cBus) -> None:
3995        """Make a driver for the part on ``bus``, which has one address.
3996
3997        :param bus: The bus the part is on.
3998        """
3999        self._native = _NativeScd4x(bus._native)

Make a driver for the part on bus, which has one address.

Parameters
  • bus: The bus the part is on.
def init(self) -> None:
4001    def init(self) -> None:
4002        """Stop any running measurement, read the serial number, and start periodic
4003        measurement.
4004
4005        :raises PamojaError: If nothing answers, or the serial number fails its checksum.
4006        """
4007        self._native.init()

Stop any running measurement, read the serial number, and start periodic measurement.

Raises
  • PamojaError: If nothing answers, or the serial number fails its checksum.
def measure(self) -> Scd4xMeasurement:
4009    def measure(self) -> Scd4xMeasurement:
4010        """Wait for the next periodic result and read it, initializing the part first if
4011        :meth:`init` has not run.
4012
4013        :returns: The carbon dioxide, temperature, and humidity.
4014        :raises PamojaError: As :meth:`init`, when no result becomes ready, and when a word
4015            fails its checksum.
4016        """
4017        return self._native.measure()

Wait for the next periodic result and read it, initializing the part first if init() has not run.

:returns: The carbon dioxide, temperature, and humidity.

Raises
  • PamojaError: As init(), when no result becomes ready, and when a word fails its checksum.
def measure_single_shot(self) -> Scd4xMeasurement:
4019    def measure_single_shot(self) -> Scd4xMeasurement:
4020        """Run one on-demand measurement on an SCD41, which takes five seconds. The part
4021        must not be measuring periodically: call :meth:`stop` first, or use this in place
4022        of :meth:`init`.
4023
4024        :returns: The measurement.
4025        :raises PamojaError: As :meth:`measure`.
4026        """
4027        return self._native.measure_single_shot()

Run one on-demand measurement on an SCD41, which takes five seconds. The part must not be measuring periodically: call stop() first, or use this in place of init().

:returns: The measurement.

Raises
def data_ready(self) -> bool:
4029    def data_ready(self) -> bool:
4030        """Ask the part whether a periodic result is waiting.
4031
4032        :returns: Whether :meth:`measure` would read without waiting.
4033        :raises PamojaError: If the transfer fails or the word fails its checksum.
4034        """
4035        return self._native.data_ready()

Ask the part whether a periodic result is waiting.

:returns: Whether measure() would read without waiting.

Raises
  • PamojaError: If the transfer fails or the word fails its checksum.
def stop(self) -> None:
4037    def stop(self) -> None:
4038        """Stop periodic measurement, after which the part takes its settings commands.
4039
4040        :raises PamojaError: If the transfer fails.
4041        """
4042        self._native.stop()

Stop periodic measurement, after which the part takes its settings commands.

Raises
  • PamojaError: If the transfer fails.
def start(self) -> None:
4044    def start(self) -> None:
4045        """Start periodic measurement.
4046
4047        :raises PamojaError: If the transfer fails.
4048        """
4049        self._native.start()

Start periodic measurement.

Raises
  • PamojaError: If the transfer fails.
def set_temperature_offset(self, milli_celsius: int) -> None:
4051    def set_temperature_offset(self, milli_celsius: int) -> None:
4052        """Set the temperature offset that compensates the part's own warmth, until power
4053        is lost.
4054
4055        :param milli_celsius: The offset to subtract, in millidegrees.
4056        :raises PamojaError: If the transfer fails.
4057        """
4058        self._native.set_temperature_offset(milli_celsius)

Set the temperature offset that compensates the part's own warmth, until power is lost.

Parameters
  • milli_celsius: The offset to subtract, in millidegrees.
Raises
  • PamojaError: If the transfer fails.
def set_sensor_altitude(self, meters: int) -> None:
4060    def set_sensor_altitude(self, meters: int) -> None:
4061        """Set the altitude the part corrects its carbon dioxide reading for.
4062
4063        :param meters: The altitude above sea level.
4064        :raises PamojaError: If the transfer fails.
4065        """
4066        self._native.set_sensor_altitude(meters)

Set the altitude the part corrects its carbon dioxide reading for.

Parameters
  • meters: The altitude above sea level.
Raises
  • PamojaError: If the transfer fails.
serial: Optional[int]
4068    @property
4069    def serial(self) -> Optional[int]:
4070        """The 48-bit serial number read at initialization, or ``None`` before it."""
4071        return self._native.serial

The 48-bit serial number read at initialization, or None before it.

class Scd4xMeasurement:

A decoded SCD4x measurement frame.

relative_humidity_percent

The relative humidity as a percentage.

celsius

The temperature in degrees Celsius.

temperature_raw

The raw temperature word.

co2_ppm

The carbon dioxide concentration in parts per million.

milli_celsius

The temperature in milli-degrees Celsius, exact in integer arithmetic.

humidity_raw

The raw humidity word.

humidity_milli_percent

The relative humidity in milli-percent.

class Sht3x:
3906class Sht3x:
3907    """A Sensirion SHT3x driven over an :class:`~pamoja.hal.I2cBus`, measuring on demand in
3908    single-shot mode.
3909
3910    >>> from pamoja.hal import I2cBus
3911    >>> bus = I2cBus.simulated([sht3x.sim.reporting(sht3x.ADDRESS_A, 30.0, 70.0)])
3912    >>> round(Sht3x(bus, sht3x.ADDRESS_A).measure().celsius, 1)
3913    30.0
3914    """
3915
3916    __slots__ = ("_native",)
3917
3918    def __init__(
3919        self,
3920        bus: I2cBus,
3921        address: int,
3922        *,
3923        repeatability: Sht3xRepeatability = Sht3xRepeatability.HIGH,
3924    ) -> None:
3925        """Make a driver for the part at ``address`` on ``bus``.
3926
3927        :param bus: The bus the part is on.
3928        :param address: ``sht3x.ADDRESS_A`` with ADDR low, ``sht3x.ADDRESS_B`` with it
3929            high.
3930        :param repeatability: How repeatable each measurement is, against how long it
3931            takes.
3932        """
3933        self._native = _NativeSht3x(
3934            bus._native, address, Sht3xRepeatability(repeatability).value
3935        )
3936
3937    def init(self) -> None:
3938        """Soft-reset the part and read its status; a status word whose checksum holds is
3939        what confirms an SHT3x answers, as the part has no id register.
3940
3941        :raises PamojaError: If nothing answers, or the status word fails its checksum.
3942        """
3943        self._native.init()
3944
3945    def measure(self) -> Sht3xMeasurement:
3946        """Run one single-shot measurement, initializing the part first if :meth:`init`
3947        has not run.
3948
3949        :returns: The checksum-checked temperature and humidity.
3950        :raises PamojaError: As :meth:`init`, and when a data word fails its checksum.
3951        """
3952        return self._native.measure()
3953
3954    def read_status(self) -> Sht3xStatus:
3955        """Read the status register, which :attr:`last_status` keeps as well.
3956
3957        :returns: The status.
3958        :raises PamojaError: If the transfer fails or the word fails its checksum.
3959        """
3960        return self._native.read_status()
3961
3962    def heater_on(self) -> None:
3963        """Switch the plausibility-check heater on, initializing the part first if needed.
3964
3965        :raises PamojaError: As :meth:`init`.
3966        """
3967        self._native.heater_on()
3968
3969    def heater_off(self) -> None:
3970        """Switch the heater off, which is its state after any reset.
3971
3972        :raises PamojaError: As :meth:`init`.
3973        """
3974        self._native.heater_off()
3975
3976    @property
3977    def last_status(self) -> Optional[Sht3xStatus]:
3978        """The status register as it was last read, or ``None`` before it has been."""
3979        return self._native.last_status

A Sensirion SHT3x driven over an ~pamoja.hal.I2cBus, measuring on demand in single-shot mode.

>>> from pamoja.hal import I2cBus
>>> bus = I2cBus.simulated([sht3x.sim.reporting(sht3x.ADDRESS_A, 30.0, 70.0)])
>>> round(Sht3x(bus, sht3x.ADDRESS_A).measure().celsius, 1)
30.0
Sht3x( bus: pamoja.hal.I2cBus, address: int, *, repeatability: Sht3xRepeatability = <Sht3xRepeatability.HIGH: 'High'>)
3918    def __init__(
3919        self,
3920        bus: I2cBus,
3921        address: int,
3922        *,
3923        repeatability: Sht3xRepeatability = Sht3xRepeatability.HIGH,
3924    ) -> None:
3925        """Make a driver for the part at ``address`` on ``bus``.
3926
3927        :param bus: The bus the part is on.
3928        :param address: ``sht3x.ADDRESS_A`` with ADDR low, ``sht3x.ADDRESS_B`` with it
3929            high.
3930        :param repeatability: How repeatable each measurement is, against how long it
3931            takes.
3932        """
3933        self._native = _NativeSht3x(
3934            bus._native, address, Sht3xRepeatability(repeatability).value
3935        )

Make a driver for the part at address on bus.

Parameters
  • bus: The bus the part is on.
  • address: sht3x.ADDRESS_A with ADDR low, sht3x.ADDRESS_B with it high.
  • repeatability: How repeatable each measurement is, against how long it takes.
def init(self) -> None:
3937    def init(self) -> None:
3938        """Soft-reset the part and read its status; a status word whose checksum holds is
3939        what confirms an SHT3x answers, as the part has no id register.
3940
3941        :raises PamojaError: If nothing answers, or the status word fails its checksum.
3942        """
3943        self._native.init()

Soft-reset the part and read its status; a status word whose checksum holds is what confirms an SHT3x answers, as the part has no id register.

Raises
  • PamojaError: If nothing answers, or the status word fails its checksum.
def measure(self) -> Sht3xMeasurement:
3945    def measure(self) -> Sht3xMeasurement:
3946        """Run one single-shot measurement, initializing the part first if :meth:`init`
3947        has not run.
3948
3949        :returns: The checksum-checked temperature and humidity.
3950        :raises PamojaError: As :meth:`init`, and when a data word fails its checksum.
3951        """
3952        return self._native.measure()

Run one single-shot measurement, initializing the part first if init() has not run.

:returns: The checksum-checked temperature and humidity.

Raises
  • PamojaError: As init(), and when a data word fails its checksum.
def read_status(self) -> Sht3xStatus:
3954    def read_status(self) -> Sht3xStatus:
3955        """Read the status register, which :attr:`last_status` keeps as well.
3956
3957        :returns: The status.
3958        :raises PamojaError: If the transfer fails or the word fails its checksum.
3959        """
3960        return self._native.read_status()

Read the status register, which last_status keeps as well.

:returns: The status.

Raises
  • PamojaError: If the transfer fails or the word fails its checksum.
def heater_on(self) -> None:
3962    def heater_on(self) -> None:
3963        """Switch the plausibility-check heater on, initializing the part first if needed.
3964
3965        :raises PamojaError: As :meth:`init`.
3966        """
3967        self._native.heater_on()

Switch the plausibility-check heater on, initializing the part first if needed.

Raises
def heater_off(self) -> None:
3969    def heater_off(self) -> None:
3970        """Switch the heater off, which is its state after any reset.
3971
3972        :raises PamojaError: As :meth:`init`.
3973        """
3974        self._native.heater_off()

Switch the heater off, which is its state after any reset.

Raises
last_status: Optional[Sht3xStatus]
3976    @property
3977    def last_status(self) -> Optional[Sht3xStatus]:
3978        """The status register as it was last read, or ``None`` before it has been."""
3979        return self._native.last_status

The status register as it was last read, or None before it has been.

class Sht3xMeasurement:

A decoded SHT3x temperature and humidity pair.

milli_celsius

The temperature in milli-degrees Celsius, exact in integer arithmetic.

celsius

The temperature in degrees Celsius.

fahrenheit

The temperature in degrees Fahrenheit.

relative_humidity

The relative humidity as a percentage.

humidity_raw

The raw humidity word.

milli_fahrenheit

The temperature in milli-degrees Fahrenheit.

milli_percent

The relative humidity in milli-percent.

temperature_raw

The raw temperature word.

class Sht3xRate(builtins.str, enum.Enum):
1501class Sht3xRate(str, enum.Enum):
1502    """How often an SHT3x in periodic mode takes a measurement."""
1503
1504    #: One measurement every two seconds.
1505    HALF_MPS = "HalfMps"
1506    #: One measurement per second.
1507    ONE_MPS = "OneMps"
1508    #: Two measurements per second.
1509    TWO_MPS = "TwoMps"
1510    #: Four measurements per second.
1511    FOUR_MPS = "FourMps"
1512    #: Ten measurements per second.
1513    TEN_MPS = "TenMps"

How often an SHT3x in periodic mode takes a measurement.

HALF_MPS = <Sht3xRate.HALF_MPS: 'HalfMps'>
ONE_MPS = <Sht3xRate.ONE_MPS: 'OneMps'>
TWO_MPS = <Sht3xRate.TWO_MPS: 'TwoMps'>
FOUR_MPS = <Sht3xRate.FOUR_MPS: 'FourMps'>
TEN_MPS = <Sht3xRate.TEN_MPS: 'TenMps'>
class Sht3xRepeatability(builtins.str, enum.Enum):
1490class Sht3xRepeatability(str, enum.Enum):
1491    """How hard an SHT3x works at one measurement, traded against time and power."""
1492
1493    #: The fastest and least precise setting.
1494    LOW = "Low"
1495    #: The middle setting.
1496    MEDIUM = "Medium"
1497    #: The slowest and most precise setting.
1498    HIGH = "High"

How hard an SHT3x works at one measurement, traded against time and power.

LOW = <Sht3xRepeatability.LOW: 'Low'>
MEDIUM = <Sht3xRepeatability.MEDIUM: 'Medium'>
HIGH = <Sht3xRepeatability.HIGH: 'High'>
class Sht3xStatus:

A decoded SHT3x status register.

humidity_tracking_alert

Whether a humidity tracking alert is set.

alert_pending

Whether at least one alert condition is pending.

command_failed

Whether the last command could not be processed.

bits

The 16-bit status word the flags were read from.

write_checksum_failed

Whether the last write failed its checksum.

heater_on

Whether the on-die heater is running.

temperature_tracking_alert

Whether a temperature tracking alert is set.

reset_detected

Whether the part has reset since the flag was last cleared.

class Tmp117:
3489class Tmp117:
3490    """A Texas Instruments TMP117 driven over an :class:`~pamoja.hal.I2cBus`, converting on
3491    demand in one-shot mode and powered down between conversions.
3492
3493    >>> from pamoja.hal import I2cBus
3494    >>> bus = I2cBus.simulated([tmp117.sim.reporting(tmp117.ADDRESS_ADD0_GND, -18.5)])
3495    >>> Tmp117(bus, tmp117.ADDRESS_ADD0_GND).measure().celsius
3496    -18.5
3497    """
3498
3499    __slots__ = ("_native",)
3500
3501    def __init__(
3502        self, bus: I2cBus, address: int, *, averaging: Tmp117Averaging = Tmp117Averaging.X8
3503    ) -> None:
3504        """Make a driver for the part at ``address`` on ``bus``.
3505
3506        :param bus: The bus the part is on.
3507        :param address: One of the ``tmp117.ADDRESS_ADD0_*`` constants, by where ADD0 is
3508            tied.
3509        :param averaging: How many conversions are averaged into each result.
3510        """
3511        self._native = _NativeTmp117(bus._native, address, int(averaging))
3512
3513    def init(self) -> None:
3514        """Check the part is a TMP117, wait for its EEPROM, and write the settings with the
3515        part in shutdown.
3516
3517        :raises PamojaError: If nothing answers, the device id is not a TMP117's, or the
3518            EEPROM never reports ready.
3519        """
3520        self._native.init()
3521
3522    def measure(self) -> Tmp117Reading:
3523        """Run one conversion and read the temperature, initializing the part first if
3524        :meth:`init` has not run.
3525
3526        :returns: The temperature.
3527        :raises PamojaError: As :meth:`init`, and when the conversion never finishes.
3528        """
3529        return self._native.measure()
3530
3531    def set_alert_limits(self, high_celsius: float, low_celsius: float) -> None:
3532        """Write the high and low limits the part compares each result against.
3533
3534        :param high_celsius: The high limit; the factory value is 192 C.
3535        :param low_celsius: The low limit; the factory value is -256 C.
3536        :raises PamojaError: If the transfer fails.
3537        """
3538        self._native.set_alert_limits(high_celsius, low_celsius)
3539
3540    def alerts(self) -> Tmp117Alerts:
3541        """Read the alert flags, including results the driver's own reads saw since the
3542        last call.
3543
3544        :returns: Whether a result was above the high limit or below the low limit.
3545        :raises PamojaError: If the transfer fails.
3546        """
3547        return self._native.alerts()
3548
3549    @property
3550    def silicon_revision(self) -> Optional[int]:
3551        """The silicon revision read at initialization, or ``None`` before it."""
3552        return self._native.silicon_revision

A Texas Instruments TMP117 driven over an ~pamoja.hal.I2cBus, converting on demand in one-shot mode and powered down between conversions.

>>> from pamoja.hal import I2cBus
>>> bus = I2cBus.simulated([tmp117.sim.reporting(tmp117.ADDRESS_ADD0_GND, -18.5)])
>>> Tmp117(bus, tmp117.ADDRESS_ADD0_GND).measure().celsius
-18.5
Tmp117( bus: pamoja.hal.I2cBus, address: int, *, averaging: Tmp117Averaging = <Tmp117Averaging.X8: 1>)
3501    def __init__(
3502        self, bus: I2cBus, address: int, *, averaging: Tmp117Averaging = Tmp117Averaging.X8
3503    ) -> None:
3504        """Make a driver for the part at ``address`` on ``bus``.
3505
3506        :param bus: The bus the part is on.
3507        :param address: One of the ``tmp117.ADDRESS_ADD0_*`` constants, by where ADD0 is
3508            tied.
3509        :param averaging: How many conversions are averaged into each result.
3510        """
3511        self._native = _NativeTmp117(bus._native, address, int(averaging))

Make a driver for the part at address on bus.

Parameters
  • bus: The bus the part is on.
  • address: One of the tmp117.ADDRESS_ADD0_* constants, by where ADD0 is tied.
  • averaging: How many conversions are averaged into each result.
def init(self) -> None:
3513    def init(self) -> None:
3514        """Check the part is a TMP117, wait for its EEPROM, and write the settings with the
3515        part in shutdown.
3516
3517        :raises PamojaError: If nothing answers, the device id is not a TMP117's, or the
3518            EEPROM never reports ready.
3519        """
3520        self._native.init()

Check the part is a TMP117, wait for its EEPROM, and write the settings with the part in shutdown.

Raises
  • PamojaError: If nothing answers, the device id is not a TMP117's, or the EEPROM never reports ready.
def measure(self) -> Tmp117Reading:
3522    def measure(self) -> Tmp117Reading:
3523        """Run one conversion and read the temperature, initializing the part first if
3524        :meth:`init` has not run.
3525
3526        :returns: The temperature.
3527        :raises PamojaError: As :meth:`init`, and when the conversion never finishes.
3528        """
3529        return self._native.measure()

Run one conversion and read the temperature, initializing the part first if init() has not run.

:returns: The temperature.

Raises
  • PamojaError: As init(), and when the conversion never finishes.
def set_alert_limits(self, high_celsius: float, low_celsius: float) -> None:
3531    def set_alert_limits(self, high_celsius: float, low_celsius: float) -> None:
3532        """Write the high and low limits the part compares each result against.
3533
3534        :param high_celsius: The high limit; the factory value is 192 C.
3535        :param low_celsius: The low limit; the factory value is -256 C.
3536        :raises PamojaError: If the transfer fails.
3537        """
3538        self._native.set_alert_limits(high_celsius, low_celsius)

Write the high and low limits the part compares each result against.

Parameters
  • high_celsius: The high limit; the factory value is 192 C.
  • low_celsius: The low limit; the factory value is -256 C.
Raises
  • PamojaError: If the transfer fails.
def alerts(self) -> Tmp117Alerts:
3540    def alerts(self) -> Tmp117Alerts:
3541        """Read the alert flags, including results the driver's own reads saw since the
3542        last call.
3543
3544        :returns: Whether a result was above the high limit or below the low limit.
3545        :raises PamojaError: If the transfer fails.
3546        """
3547        return self._native.alerts()

Read the alert flags, including results the driver's own reads saw since the last call.

:returns: Whether a result was above the high limit or below the low limit.

Raises
  • PamojaError: If the transfer fails.
silicon_revision: Optional[int]
3549    @property
3550    def silicon_revision(self) -> Optional[int]:
3551        """The silicon revision read at initialization, or ``None`` before it."""
3552        return self._native.silicon_revision

The silicon revision read at initialization, or None before it.

class Tmp117Alerts:

The TMP117's alert flags: whether a result since they were last read crossed a limit.

high

A result was above the high limit.

low

A result was below the low limit.

class Tmp117Averaging(enum.IntEnum):
462class Tmp117Averaging(enum.IntEnum):
463    """How many conversions a TMP117 averages into one result, as its register code."""
464
465    #: No averaging: each result is one 15.5 ms conversion.
466    NONE = 0
467    #: Eight conversions, the factory setting.
468    X8 = 1
469    #: Thirty-two conversions.
470    X32 = 2
471    #: Sixty-four conversions.
472    X64 = 3

How many conversions a TMP117 averages into one result, as its register code.

NONE = <Tmp117Averaging.NONE: 0>
X8 = <Tmp117Averaging.X8: 1>
X32 = <Tmp117Averaging.X32: 2>
X64 = <Tmp117Averaging.X64: 3>
class Tmp117Config:

A TMP117 configuration register, field by field.

cycle

The conversion-cycle code, 0..=7.

therm_mode

Whether the limits act as a therm hysteresis band rather than as alerts.

high_alert

Whether a result went above the high limit.

data_ready

Whether a conversion has completed since the register was last read.

eeprom_busy

Whether an EEPROM write is still in progress.

mode

The conversion-mode code: 0 continuous, 1 shutdown, 3 one-shot.

averaging

The averaging code, 0..=3.

alert_pin_data_ready

Whether the ALERT pin reflects data ready rather than the alert flags.

soft_reset

Whether writing this triggers a software reset.

alert_active_high

Whether the ALERT pin is active high.

low_alert

Whether a result went below the low limit.

class Tmp117Reading:

A TMP117 temperature result.

micro_celsius

The temperature in micro-degrees Celsius, exact in integer arithmetic.

celsius

The temperature in degrees Celsius.

raw

The temperature register, 7.8125 millidegrees Celsius per count.

ads1115 = <pamoja.sensors._Ads1115 object>
bme280 = <pamoja.sensors._Bme280 object>
bmp280 = <pamoja.sensors._Bmp280 object>
ds18b20 = <pamoja.sensors._Ds18b20 object>
hdc1080 = <pamoja.sensors._Hdc1080 object>
ina219 = <pamoja.sensors._Ina219 object>
ina226 = <pamoja.sensors._Ina226 object>
opt3001 = <pamoja.sensors._Opt3001 object>
scd4x = <pamoja.sensors._Scd4x object>
sht3x = <pamoja.sensors._Sht3x object>
tmp117 = <pamoja.sensors._Tmp117 object>