mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 02:02:51 +00:00
[MAX31888] Add temperature sensor (#13567)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
co-authored by
pre-commit-ci-lite[bot]
J. Nick Koston
parent
a68cf669aa
commit
f9f41ef16e
@@ -343,6 +343,7 @@ esphome/components/mapping/* @clydebarrow
|
||||
esphome/components/matrix_keypad/* @ssieb
|
||||
esphome/components/max17043/* @blacknell
|
||||
esphome/components/max31865/* @DAVe3283
|
||||
esphome/components/max31888/* @JiriPrchal
|
||||
esphome/components/max44009/* @berfenger
|
||||
esphome/components/max6956/* @looping40
|
||||
esphome/components/max7219digit/* @rspaargaren
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
CODEOWNERS = ["@JiriPrchal"]
|
||||
DOMAIN = "max31888"
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "max31888.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::max31888 {
|
||||
|
||||
ESPHOME_LOG_TAG(TAG, "max31888");
|
||||
|
||||
static constexpr uint32_t CONVERSION_TIMEOUT_ID = 0;
|
||||
|
||||
static constexpr uint8_t MAX31888_COMMAND_START_CONVERSION = 0x44;
|
||||
static constexpr uint8_t MAX31888_COMMAND_READ = 0x33;
|
||||
static constexpr uint8_t MAX31888_COMMAND_SOFT_RESET = 0x82;
|
||||
static constexpr uint8_t MAX31888_REGISTER_FIFO_DATA = 0x08;
|
||||
static constexpr uint8_t MAX31888_FIFO_READ_LENGTH = 0x01; // number of bytes to read, minus one
|
||||
static constexpr uint16_t MAX31888_CONVERSION_TIME_MS = 20;
|
||||
static constexpr float MAX31888_DEGREES_PER_LSB = 0.005f;
|
||||
|
||||
// Sends a command and checks the checksum the device appends to it (Maxim CRC-16 over the command byte,
|
||||
// sent inverted and low byte first)
|
||||
bool MAX31888Sensor::send_checked_command_(uint8_t command) {
|
||||
if (!this->send_command_(command)) {
|
||||
this->status_set_warning(LOG_STR("bus reset failed"));
|
||||
return false;
|
||||
}
|
||||
const uint8_t low = this->bus_->read8();
|
||||
const uint8_t high = this->bus_->read8();
|
||||
if (crc16(&command, 1, 0, 0xa001, false, true) != encode_uint16(high, low)) {
|
||||
this->status_set_warning(LOG_STR("command checksum invalid"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MAX31888Sensor::setup() {
|
||||
if (!this->check_address_or_index_())
|
||||
return;
|
||||
if (!this->send_checked_command_(MAX31888_COMMAND_SOFT_RESET)) {
|
||||
this->mark_failed();
|
||||
}
|
||||
}
|
||||
|
||||
void MAX31888Sensor::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "MAX31888 Sensor:");
|
||||
if (this->address_ == 0) {
|
||||
ESP_LOGW(TAG, " Unable to select an address");
|
||||
return;
|
||||
}
|
||||
LOG_ONE_WIRE_DEVICE(this);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
void MAX31888Sensor::update() {
|
||||
if (this->address_ == 0)
|
||||
return;
|
||||
|
||||
if (!this->send_checked_command_(MAX31888_COMMAND_START_CONVERSION)) {
|
||||
this->publish_state(NAN);
|
||||
return;
|
||||
}
|
||||
|
||||
this->set_timeout(CONVERSION_TIMEOUT_ID, MAX31888_CONVERSION_TIME_MS, [this] {
|
||||
int16_t raw;
|
||||
if (!this->read_temperature_(raw)) {
|
||||
this->publish_state(NAN);
|
||||
return;
|
||||
}
|
||||
const float temperature = raw * MAX31888_DEGREES_PER_LSB;
|
||||
ESP_LOGD(TAG, "'%s': Got Temperature=%.3f°C", this->get_name().c_str(), temperature);
|
||||
this->status_clear_warning();
|
||||
this->publish_state(temperature);
|
||||
});
|
||||
}
|
||||
|
||||
bool MAX31888Sensor::read_temperature_(int16_t &raw) {
|
||||
// The checksum covers the command and its two arguments as well as the data
|
||||
uint8_t frame[7] = {MAX31888_COMMAND_READ, MAX31888_REGISTER_FIFO_DATA, MAX31888_FIFO_READ_LENGTH};
|
||||
if (!this->send_command_(frame[0])) {
|
||||
this->status_set_warning(LOG_STR("bus reset failed"));
|
||||
return false;
|
||||
}
|
||||
this->bus_->write8(frame[1]);
|
||||
this->bus_->write8(frame[2]);
|
||||
for (size_t i = 3; i < sizeof(frame); i++) {
|
||||
frame[i] = this->bus_->read8();
|
||||
}
|
||||
if (crc16(frame, 5, 0, 0xa001, false, true) != encode_uint16(frame[6], frame[5])) {
|
||||
this->status_set_warning(LOG_STR("checksum invalid"));
|
||||
return false;
|
||||
}
|
||||
raw = static_cast<int16_t>(encode_uint16(frame[3], frame[4]));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace esphome::max31888
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/one_wire/one_wire.h"
|
||||
|
||||
namespace esphome::max31888 {
|
||||
|
||||
class MAX31888Sensor final : public PollingComponent, public sensor::Sensor, public one_wire::OneWireDevice {
|
||||
public:
|
||||
void setup() override;
|
||||
void update() override;
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
bool send_checked_command_(uint8_t command);
|
||||
/// Reads the latest conversion from the FIFO; false when the bus or the checksum fails
|
||||
bool read_temperature_(int16_t &raw);
|
||||
};
|
||||
|
||||
} // namespace esphome::max31888
|
||||
@@ -0,0 +1,36 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import one_wire, sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
max31888_ns = cg.esphome_ns.namespace("max31888")
|
||||
|
||||
MAX31888Sensor = max31888_ns.class_(
|
||||
"MAX31888Sensor",
|
||||
cg.PollingComponent,
|
||||
sensor.Sensor,
|
||||
one_wire.OneWireDevice,
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
sensor.sensor_schema(
|
||||
MAX31888Sensor,
|
||||
unit_of_measurement=UNIT_CELSIUS,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
.extend(one_wire.one_wire_device_schema())
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
var = await sensor.new_sensor(config)
|
||||
await cg.register_component(var, config)
|
||||
await one_wire.register_one_wire_device(var, config)
|
||||
@@ -10,6 +10,7 @@ static const uint8_t DALLAS_MODEL_DS1822 = 0x22;
|
||||
static const uint8_t DALLAS_MODEL_DS18B20 = 0x28;
|
||||
static const uint8_t DALLAS_MODEL_DS1825 = 0x3B;
|
||||
static const uint8_t DALLAS_MODEL_DS28EA00 = 0x42;
|
||||
static const uint8_t MAXIM_MODEL_MAX31888 = 0x54;
|
||||
|
||||
const uint8_t ONE_WIRE_ROM_SELECT = 0x55;
|
||||
const uint8_t ONE_WIRE_ROM_SEARCH = 0xF0;
|
||||
@@ -76,6 +77,8 @@ const LogString *OneWireBus::get_model_str(uint8_t model) {
|
||||
return LOG_STR("DS1825");
|
||||
case DALLAS_MODEL_DS28EA00:
|
||||
return LOG_STR("DS28EA00");
|
||||
case MAXIM_MODEL_MAX31888:
|
||||
return LOG_STR("MAX31888");
|
||||
default:
|
||||
return LOG_STR("Unknown");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
sensor:
|
||||
- platform: max31888
|
||||
one_wire_id: one_wire_bus
|
||||
address: 0x1C0000031EDD2A54
|
||||
name: MAX31888 Temperature 1
|
||||
- platform: max31888
|
||||
one_wire_id: one_wire_bus
|
||||
name: MAX31888 Temperature 2
|
||||
index: 1
|
||||
@@ -0,0 +1,3 @@
|
||||
packages:
|
||||
one_wire: !include ../../test_build_components/common/one_wire/esp32-idf.yaml
|
||||
max31888: !include common.yaml
|
||||
@@ -0,0 +1,3 @@
|
||||
packages:
|
||||
one_wire: !include ../../test_build_components/common/one_wire/esp8266-ard.yaml
|
||||
max31888: !include common.yaml
|
||||
@@ -0,0 +1,3 @@
|
||||
packages:
|
||||
one_wire: !include ../../test_build_components/common/one_wire/rp2040-ard.yaml
|
||||
max31888: !include common.yaml
|
||||
@@ -125,6 +125,11 @@ Components using `modbus` packages automatically get `uart` as well.
|
||||
- **RP2040**: SCL=GPIO5, SDA=GPIO4
|
||||
- **BK72xx**: SCL=P20, SDA=P21
|
||||
|
||||
### 1-Wire
|
||||
- **ESP32 IDF**: GPIO4
|
||||
- **ESP8266**: GPIO13
|
||||
- **RP2040**: GPIO10
|
||||
|
||||
### I2C Low Frequency (10kHz)
|
||||
Same pin allocations as standard I2C, but with 10kHz frequency for components requiring slower speeds.
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Common 1-Wire configuration for esp32-idf tests
|
||||
# Provides a shared 1-Wire bus that all components can use
|
||||
|
||||
substitutions:
|
||||
one_wire_pin: GPIO4
|
||||
|
||||
one_wire:
|
||||
- platform: gpio
|
||||
id: one_wire_bus
|
||||
pin: ${one_wire_pin}
|
||||
@@ -0,0 +1,10 @@
|
||||
# Common 1-Wire configuration for esp8266-ard tests
|
||||
# Provides a shared 1-Wire bus that all components can use
|
||||
|
||||
substitutions:
|
||||
one_wire_pin: GPIO13
|
||||
|
||||
one_wire:
|
||||
- platform: gpio
|
||||
id: one_wire_bus
|
||||
pin: ${one_wire_pin}
|
||||
@@ -0,0 +1,10 @@
|
||||
# Common 1-Wire configuration for rp2040-ard tests
|
||||
# Provides a shared 1-Wire bus that all components can use
|
||||
|
||||
substitutions:
|
||||
one_wire_pin: GPIO10
|
||||
|
||||
one_wire:
|
||||
- platform: gpio
|
||||
id: one_wire_bus
|
||||
pin: ${one_wire_pin}
|
||||
Reference in New Issue
Block a user