Skip to content

Instantly share code, notes, and snippets.

@glw119
Created November 8, 2025 13:45
Show Gist options
  • Select an option

  • Save glw119/b3206fabddf9aeb5a957b253c58444c1 to your computer and use it in GitHub Desktop.

Select an option

Save glw119/b3206fabddf9aeb5a957b253c58444c1 to your computer and use it in GitHub Desktop.
DELL电源PMBus读取数据
esphome:
name: dell-power-supply-monitor
friendly_name: dell_power_supply_monitor
includes:
- dell_power_supply/main.hpp
- dell_power_supply/pmbus.cpp
- dell_power_supply/pmbus.h
esp8266:
board: d1_mini
api:
encryption:
key: "111"
web_server:
port: 80
ota:
- platform: esphome
password: "111"
wifi:
networks:
- ssid: !secret iot_intranet_ssid
password: !secret wifi_password
priority: 100
ap:
ssid: "Dell-Power-Supply-Monitor-D1"
password: "111"
channel: 1
captive_portal:
external_components:
- source:
type: git
url: https://github.com/robertklep/esphome-custom-component
components: [ custom, custom_component ]
i2c:
sda: D2
scl: D1
scan: true
id: pmbus_i2c_bus
frequency: 100kHz
sensor:
- platform: dht
pin: D7
temperature:
name: "HDD Case Inlet Temperature"
humidity:
name: "HDD Case Inlet Humidity"
update_interval: 60s
- platform: dht
pin: D6
temperature:
name: "HDD Case Outlet Temperature"
humidity:
name: "HDD Case Outlet Humidity"
update_interval: 60s
- platform: wifi_signal
name: "WiFi Signal Sensor"
update_interval: 60s
- platform: custom
lambda: |-
auto pwr = new DellPower();
App.register_component(pwr);
return {pwr->v_in,pwr->i_in,pwr->w_in,pwr->e_in,pwr->v_out,pwr->i_out,pwr->w_out,pwr->temp1,pwr->temp2,pwr->temp3,pwr->fan};
sensors:
- name: "Input voltage"
accuracy_decimals: 1
unit_of_measurement: V
filters:
- lambda: 'return (x < 0 || x > 250) ? NAN : x;'
- throttle: 1s # 添加限流,每秒最多更新一次
- delta: 0.1 # 变化小于0.1V时不更新
- name: "Input Current"
accuracy_decimals: 1
unit_of_measurement: A
filters:
- lambda: 'return (x < 0 || x > 50) ? NAN : x;'
- throttle: 1s # 添加限流,每秒最多更新一次
- delta: 0.1 # 变化小于0.1V时不更新
- name: "Input Power"
accuracy_decimals: 1
unit_of_measurement: W
filters:
- lambda: 'return (x < 0 || x > 600) ? NAN : x;'
- throttle: 1s # 添加限流,每秒最多更新一次
- delta: 0.1 # 变化小于0.1V时不更新
- name: "E_in"
accuracy_decimals: 1
unit_of_measurement: "%"
filters:
- throttle: 1s # 添加限流,每秒最多更新一次
- delta: 0.1 # 变化小于0.1V时不更新
- name: "Output Voltage"
accuracy_decimals: 1
unit_of_measurement: V
filters:
- lambda: 'return (x < 10 || x > 15) ? NAN : x;'
- throttle: 1s # 添加限流,每秒最多更新一次
- delta: 0.1 # 变化小于0.1V时不更新
- name: "Output Current"
accuracy_decimals: 1
unit_of_measurement: A
filters:
- lambda: 'return (x < 0 || x > 60) ? NAN : x;'
- throttle: 1s # 添加限流,每秒最多更新一次
- delta: 0.1 # 变化小于0.1V时不更新
- name: "Output Power"
accuracy_decimals: 1
unit_of_measurement: W
filters:
- lambda: 'return (x < 0 || x > 500) ? NAN : x;'
- throttle: 1s # 添加限流,每秒最多更新一次
- delta: 0.1 # 变化小于0.1V时不更新
- name: "Temp 1"
accuracy_decimals: 1
unit_of_measurement: °C
filters:
- lambda: 'return (x < 0 || x > 100) ? NAN : x;'
- throttle: 1s # 添加限流,每秒最多更新一次
- delta: 0.1 # 变化小于0.1V时不更新
- name: "Temp 2"
accuracy_decimals: 1
unit_of_measurement: °C
filters:
- lambda: 'return (x < 0 || x > 100) ? NAN : x;'
- throttle: 1s # 添加限流,每秒最多更新一次
- delta: 0.1 # 变化小于0.1V时不更新
- name: "Temp 3"
accuracy_decimals: 1
unit_of_measurement: °C
filters:
- lambda: 'return (x < 0 || x > 100) ? NAN : x;'
- throttle: 1s # 添加限流,每秒最多更新一次
- delta: 0.1 # 变化小于0.1V时不更新
- name: "Fan Speed"
accuracy_decimals: 1
unit_of_measurement: RPM
filters:
- lambda: 'return (x < 0 || x > 5000) ? NAN : x;'
- throttle: 1s # 添加限流,每秒最多更新一次
- delta: 0.1 # 变化小于0.1V时不更新
#include "pmbus.h"
#include "esphome.h"
PMBus psu;
class DellPower : public PollingComponent {
public:
Sensor *v_in = new Sensor();
Sensor *i_in = new Sensor();
Sensor *w_in = new Sensor();
Sensor *e_in = new Sensor();
Sensor *v_out = new Sensor();
Sensor *i_out = new Sensor();
Sensor *w_out = new Sensor();
//Sensor *e_out = new Sensor();
Sensor *temp1 = new Sensor();
Sensor *temp2 = new Sensor();
Sensor *temp3 = new Sensor();
Sensor *fan = new Sensor();
DellPower(): PollingComponent(3000) { }
// 这个3000大概指的是3000毫秒更新一次信息吧
void setup() override {
Wire.setClock(100000);
psu.readMFR();
ESP_LOGD("PSU", "manf.: %s", psu.mfr_id);
ESP_LOGD("PSU", "model: %s", psu. mfr_model);
ESP_LOGD("PSU", "revision: %s", psu.mfr_revision);
ESP_LOGD("PSU", "location: %s", psu.mfr_location);
ESP_LOGD("PSU", "date: %s", psu.mfr_date);
ESP_LOGD("PSU", "serial: %s", psu.mfr_serial);
}
void update() override {
psu.scan();
v_in->publish_state(psu.V_in);
i_in->publish_state(psu.I_in);
w_in->publish_state(psu.W_in);
e_in->publish_state(psu.E_in);
// v_out->publish_state(psu.V_out);
v_out->publish_state(psu.I_out != 0 ? psu.W_out/psu.I_out : psu.V_out);
i_out->publish_state(psu.I_out);
w_out->publish_state(psu.W_out);
//e_out->publish_state(psu.E_out);
temp1->publish_state(psu.T[0]);
temp2->publish_state(psu.T[1]);
temp3->publish_state(psu.T[2]);
fan->publish_state(psu.fan[0]);
}
};
/*
* Copyright (c) 2024 Tomosawa
* https://github.com/Tomosawa/
* All rights reserved
*/
#pragma GCC diagnostic warning "-Wunused-variable"
#define DIAGNOSTICS 1
#include "pmbus.h"
#define PMBUS_ADDRESS 0x58
// PMBus 命令定义
// 基本信息
#define MFR_ID 0x99
#define MFR_MODEL 0x9A
#define MFR_REVISION 0x9B
#define MFR_LOCATION 0x9C
#define MFR_DATE 0x9D
#define MFR_SERIAL 0x9E
// 规格信息
#define MFR_VIN_MIN 0xA0
#define MFR_VIN_MAX 0xA1
#define MFR_IIN_MAX 0xA2
#define MFR_PIN_MAX 0xA3
#define MFR_VOUT_MIN 0xA4
#define MFR_VOUT_MAX 0xA5
#define MFR_IOUT_MAX 0xA6
#define MFR_POUT_MAX 0xA7
#define MFR_TAMBIENT_MAX 0xA8
#define MFR_TAMBIENT_MIN 0xA9
// 输入输出信息
#define READ_EIN 0x86
#define READ_EOUT 0x87
#define READ_VIN 0x88
#define READ_IIN 0x89
#define READ_VCAP 0x8A
#define READ_VOUT 0x8B
#define READ_IOUT 0x8C
#define READ_POUT 0x96
#define READ_PIN 0x97
// 温度相关
#define READ_TEMPERATURE_1 0x8D
#define READ_TEMPERATURE_2 0x8E
#define READ_TEMPERATURE_3 0x8F
#define READ_FAN_SPEED_1 0x90
// 参数设置
#define VOUT_COMMAND 0x21
#define VOUT_MAX 0x24
#define FAN_COMMAND_1 0x3B
#define VOUT_OV_FAULT_LIMIT 0x40
#define VOUT_OV_FAULT_RESPONSE 0x41
#define VOUT_OV_WARN_LIMIT 0x42
#define VOUT_UV_FAULT_LIMIT 0x44
#define VOUT_UV_FAULT_RESPONSE 0x45
#define IOUT_OC_FAULT_LIMIT 0x46
#define IOUT_OC_FAULT_RESPONSE 0x47
#define IOUT_OC_WARN_LIMIT 0x4A
#define OT_FAULT_LIMIT 0x4F
#define OT_FAULT_RESPONSE 0x50
#define OT_WARN_LIMIT 0x51
#define VIN_OV_FAULT_LIMIT 0x55
#define VIN_UV_W ARN_LIMIT 0x58
#define VIN_UV_FAULT_LIMIT 0x59
#define COEFFICIENTS 0x30
#define VOUT_MODE 0x20
#define WRITE_PROTECT 0x10
/*
*/
PMBus::PMBus()
{
// I2C = &Wire;
}
/**
* 初始化PMBus模块。
*
* @param pson_pin PSON引脚的编号。
* @param pskill_pin PSKILL引脚的编号。
* @param Debug_Serial 用于调试信息的串行流对象。
* @param i2c I2C通信接口对象,如果为null则不进行I2C通信。
* @return 返回0表示初始化成功。
*/
int PMBus::init()
{
delay(500);
return 0;
}
/*
* 获取数据
*/
int PMBus::scan()
{
// 判断时间间隔1秒才执行
static u_long last_scan = 0;
u_long msecs = millis();
if ((msecs - last_scan) < 1000)
{
return 0;
}
last_scan = msecs;
// 判断设备是否在线
if (!checkDeviceOnline())
{
return 0;
}
// 读取厂商信息,仅一次
if (!bReadMFR)
{
readMFR();
// 同时读取只需要读一次的参数
isVOutLinear = GetVOutFormat();
// ESP_LOGD("VOUT isLinearFormat=");
// ESP_LOGD(isVOutLinear);
exponent = readVoutMode(VOUT_MODE);
// ESP_LOGD("VOUT exponent=");
// ESP_LOGD(exponent);
//指定为-1,否则某些电源是-9会有问题
exponent = -1;
// 读取 COEFFICIENTS
readCoefficients(COEFFICIENTS, &coeff);
// 解除写入保护
write_byte(WRITE_PROTECT, 0x00);
uint8_t fanconfig = read_byte(0x3A);
// ESP_LOGD(String(fanconfig,BIN));
}
delay(1);
E_in = read_linear(READ_EIN);
delay(1);
E_out = read_linear(READ_EOUT);
delay(1);
V_in = read_linear(READ_VIN);
delay(1);
I_in = read_linear(READ_IIN);
delay(1);
W_in = read_linear(READ_PIN);
delay(1);
V_out = read_linear16(READ_VOUT) / 1000.0;
delay(1);
I_out = read_linear(READ_IOUT);
delay(1);
W_out = read_linear(READ_POUT);
delay(1);
T[0] = read_linear(READ_TEMPERATURE_1);
delay(1);
T[1] = read_linear(READ_TEMPERATURE_2);
delay(1);
T[2] = read_linear(READ_TEMPERATURE_3);
delay(1);
fan[0] = read_linear(READ_FAN_SPEED_1);
delay(1);
readFanCommand();
return 1;
}
/*
* 清除状态
*/
void PMBus::clear_faults()
{
Wire.beginTransmission(PMBUS_ADDRESS);
Wire.write(0x03);
Wire.endTransmission(true);
}
void PMBus::write_byte(uint8_t reg, uint8_t value)
{
Wire.beginTransmission(PMBUS_ADDRESS);
Wire.write(reg);
Wire.write(value);
Wire.endTransmission(true);
}
uint8_t PMBus::read_byte(uint8_t reg)
{
Wire.beginTransmission(PMBUS_ADDRESS);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(PMBUS_ADDRESS, 1, 1);
return Wire.read();
}
uint16_t PMBus::read_word(uint8_t reg)
{
Wire.beginTransmission(PMBUS_ADDRESS);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(PMBUS_ADDRESS, 2);
uint16_t dataRaw = 0;
if (Wire.available() >= 2)
{
// 读取高字节和低字节
uint8_t lowByte = Wire.read();
uint8_t highByte = Wire.read();
// 将高字节和低字节组合为16位的原始值
dataRaw = (highByte << 8) | lowByte;
}
return dataRaw;
}
void PMBus::write_word(uint8_t reg, uint16_t value)
{
// 将16位值分成两个字节
uint8_t value_lo = value & 0xFF; // 低位字节
uint8_t value_hi = (value >> 8) & 0xFF; // 高位字节
// 开始I2C传输
Wire.beginTransmission(PMBUS_ADDRESS);
// 发送寄存器地址
Wire.write(reg);
// 发送数据,先发送高位字节,再发送低位字节
Wire.write(value_lo);
Wire.write(value_hi);
// 结束I2C传输,确保数据被发送
Wire.endTransmission();
}
String PMBus::read_string(uint8_t reg)
{
int len = 0;
len = (int)read_byte(reg);
String result;
Wire.beginTransmission(PMBUS_ADDRESS);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(PMBUS_ADDRESS, len, 1);
for (int i = 0; i < len; i++)
{
int readData = Wire.read();
if (isPrintable(readData))
result += (char)readData;
}
return result;
}
void PMBus::read_block(uint8_t reg, int bytes, uint8_t *buffer)
{
Wire.beginTransmission(PMBUS_ADDRESS);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(PMBUS_ADDRESS, bytes, 1);
for (int i = 0; i < bytes; ++i)
{
buffer[i] = Wire.read();
}
}
float PMBus::read_linear(uint8_t reg)
{
uint16_t linear;
linear = read_word(reg);
// ESP_LOGD("Read register: 0x");
// ESP_LOGD(reg, HEX);
return linear11ToFloat(linear);
}
uint16_t PMBus::convertHex2Dec(uint16_t hexData)
{
// 将输入的十进制数视为十六进制数,直接返回其对应的十进制值
uint16_t decValue = (hexData / 1000) * 4096 + ((hexData % 1000) / 100) * 256 + ((hexData % 100) / 10) * 16 + (hexData % 10);
return decValue;
}
float PMBus::read_linear16(uint8_t reg)
{
uint16_t linear;
linear = read_word(reg);
// 根据VOUT_MODE中的 4:0 的值是-9进行转换
return ulinear16ToFloat(linear);
}
float PMBus::readVout(uint8_t reg)
{
// 读取 VOUT 寄存器
uint16_t rawVout;
rawVout = read_word(reg);
// ESP_LOGD("VOut_raw:");
// ESP_LOGD(rawVout);
// 判断格式
if (isVOutLinear)
{
// 计算 LINEAR 格式电压
float voltage = rawVout * pow(2, exponent); // LINEAR11
return voltage;
}
else
{
// 计算 DIRECT 格式电压
// 计算实际电压
float actualVoltage = (rawVout * coeff.m / pow(2, coeff.R)) + coeff.b;
return actualVoltage;
}
}
/*
* 将LINEAR11格式转换为浮点数
*/
float PMBus::linear11ToFloat(uint16_t data)
{
// ESP_LOGD("linear11ToFloat raw_data=");
// ESP_LOGD(data);
int16_t exponent11 = (data >> 11) & 0x1F; // 获取5位指数
// ESP_LOGD("linear11ToFloat exponent11=");
// ESP_LOGD(exponent11);
if (exponent11 > 15)
{
exponent11 = exponent11 - 32; // 如果指数是负数,进行调整
}
int16_t mantissa = data & 0x7FF; // 获取11位尾数
if (mantissa > 1023)
{
mantissa = mantissa - 2048; // 处理尾数的符号
}
// ESP_LOGD("linear11ToFloat mantissa=");
// ESP_LOGD(mantissa);
// ESP_LOGD("linear11ToFloat result=");
// ESP_LOGD(mantissa * pow(2, exponent11));
return mantissa * pow(2, exponent11); // 计算最终的浮点数值
}
// 根据VOUT_MODE中的比例因子转换ULINEAR16格式
float PMBus::ulinear16ToFloat(uint16_t data)
{
uint16_t dec_data = convertHex2Dec(data);
return dec_data * pow(2, exponent);
}
void PMBus::write_linear(uint8_t reg, float value)
{
uint16_t linear = float2linear(value);
write_word(reg, linear);
}
float PMBus::read_direct(uint8_t reg)
{
Coefficient_t coeff;
readCoefficients(COEFFICIENTS, &coeff);
uint16_t data;
data = read_word(reg);
return (data * pow(10, 0 - coeff.R) - coeff.b) / coeff.m;
}
// 读取VOUT_MODE寄存器
int8_t PMBus::readVoutMode(uint8_t reg)
{
Wire.beginTransmission(PMBUS_ADDRESS);
Wire.write(reg); // 请求VOUT_MODE寄存器
Wire.endTransmission(false);
Wire.requestFrom(PMBUS_ADDRESS, 1); // 请求1字节数据
// 确保有数据可读,避免潜在的问题
if (Wire.available() < 1)
{
// Serial.println("Error: No data available from VOUT_MODE register");
return 0; // 错误处理,返回 0 或其他默认值
}
uint8_t voutMode = Wire.read(); // 读取VOUT_MODE寄存器的值
// VOUT_MODE 的低5位包含比例因子指数(通常表示为2的幂)
uint8_t exponent = voutMode & 0x1F;
if (exponent > 15)
{
exponent = exponent - 32; // 如果指数是负数,进行调整
}
return exponent;
}
bool PMBus::GetVOutFormat()
{
// 读取 VOUT_MODE 寄存器
Wire.beginTransmission(PMBUS_ADDRESS);
Wire.write(VOUT_MODE); // VOUT_MODE 寄存器地址
Wire.endTransmission(false);
Wire.requestFrom(PMBUS_ADDRESS, 1); // 请求 1 字节
if (Wire.available() < 1)
{
// ESP_LOGD("Error: Insufficient data available for VOUT_MODE");
return false; // 错误处理
}
uint8_t voutMode = Wire.read(); // 读取 VOUT_MODE 值
// 检查 VOUT_MODE 的位来判断格式
// 假设 VOUT_MODE 的位 0 表示是否使用 LINEAR 格式
// 你需要根据具体的设备文档调整这部分逻辑
if (voutMode & 0x01)
{ // 假设低位为 1 表示 LINEAR 格式
return true; // LINEAR 格式
}
else
{
return false; // DIRECT 格式
}
}
/*
* 读COEFFICIENTS参数
*/
void PMBus::readCoefficients(uint8_t reg, Coefficient_t *coeff)
{
// byte regCS = ((0xFF - (reg + (PMBUS_ADDRESS << 1))) + 1) & 0xFF;
// Wire.beginTransmission(PMBUS_ADDRESS);
// Wire.write(reg);
// Wire.write(regCS);
// Wire.endTransmission(false);
// Wire.requestFrom(PMBUS_ADDRESS, 5, 1);
// uint8_t byte1 = Wire.read();
// uint8_t byte2 = Wire.read();
// uint8_t byte3 = Wire.read();
// uint8_t byte4 = Wire.read();
// uint8_t byte5 = Wire.read();
// coeff->m = byte1 | (byte2 << 8);
// coeff->b = byte3 | (byte4 << 8);
// coeff->R = byte5;
Wire.beginTransmission(PMBUS_ADDRESS);
Wire.write(reg); // COEFFICIENTS 命令地址
Wire.endTransmission(false);
Wire.requestFrom(PMBUS_ADDRESS, 6); // 请求 6 字节的数据
if (Wire.available() < 6)
{
// Serial.println("Error: Insufficient data available for COEFFICIENTS");
return;
}
// 读取 M, B 和 R 值
coeff->m = (Wire.read() | (Wire.read() << 8)); // 读取 2 字节 M
coeff->b = (Wire.read() | (Wire.read() << 8)); // 读取 2 字节 B
coeff->R = Wire.read(); // 读取 1 字节 R
Wire.read();
// ESP_LOGD("Coefficient_M: ");
// ESP_LOGD(coeff->m);
// ESP_LOGD("Coefficient_B: ");
// ESP_LOGD(coeff->b);
// ESP_LOGD("Coefficient_R: ");
// ESP_LOGD(coeff->R);
}
float PMBus::linear2float(uint16_t u16)
{
float value = 0;
UniLinear uniLinear;
uniLinear.u16 = u16;
value = uniLinear.linear.y * pow(2.0f, uniLinear.linear.n);
return value;
}
uint16_t PMBus::float2linear(float value)
{
UniLinear uniLinear;
// 初始化为避免未初始化的警告
uniLinear.u16 = 0;
// 计算n的值,即所需的偏移量
// 因为n是5位,所以它的范围是从-15到15(包括0)
int n = floor(log2(value));
if (n < -15)
n = -15; // 如果n太小,则将其限制在最小值
if (n > 15)
n = 15; // 如果n太大,则将其限制在最大值
// 计算y的值,即偏移量调整后的值
// y应该是有符号的,所以需要将其转换为11位有符号整数
int y = round(value / pow(2.0f, n));
if (y < -2048)
y = -2048; // 如果y太小,则将其限制在最小值
if (y > 2047)
y = 2047; // 如果y太大,则将其限制在最大值
// 将计算出的y和n值放入联合体中
uniLinear.linear.y = y;
uniLinear.linear.n = n;
// 返回联合体中的u16值
return uniLinear.u16;
}
uint16_t PMBus::convertlinear11(uint16_t value)
{
// int16_t mantissa = value << (-exponent); // 计算 mantissa,根据 exponent 进行位移
// // 将 exponent 和 mantissa 打包为 16-bit 数据
// uint16_t linear11Value = (mantissa & 0x07FF) | ((exponent & 0x1F) << 11);
// return linear11Value;
// 计算 mantissa,根据 exponent 进行位移或缩放
int16_t mantissa = (int16_t)(value * pow(2, -exponent));
// 将 exponent 和 mantissa 打包为 16-bit 数据
uint16_t linear11Value = (mantissa & 0x07FF) | ((exponent & 0x1F) << 11);
return linear11Value;
}
bool PMBus::checkOnOffState()
{
if (V_out < 1)
return false;
else
return true;
}
bool PMBus::checkDeviceOnline()
{
Wire.beginTransmission(PMBUS_ADDRESS);
byte error = Wire.endTransmission();
if (error != 0)
{
return false;
}
return true;
}
void PMBus::readMFR()
{
mfr_id = read_string(MFR_ID);
delay(1);
mfr_model = read_string(MFR_MODEL);
delay(1);
mfr_revision = read_string(MFR_REVISION);
delay(1);
mfr_location = read_string(MFR_LOCATION);
delay(1);
mfr_date = read_string(MFR_DATE);
delay(1);
mfr_serial = read_string(MFR_SERIAL);
delay(1);
bReadMFR = true;
// ESP_LOGD("manf.: " + mfr_id);
// ESP_LOGD("model: " + mfr_model);
// ESP_LOGD("revision: " + mfr_revision);
// ESP_LOGD("location: " + mfr_location);
// ESP_LOGD("date: " + mfr_date);
// ESP_LOGD("serial: " + mfr_serial);
}
void PMBus::recordTurnOnTime()
{
turn_on_time = millis();
}
void PMBus::getRunTime()
{
total_power_on = millis() - turn_on_time;
// int days, years;
// days = (int)((long int)total_power_on / 86400l);
// years = days / 365;
// char text[50];
// sprintf(text, "on time: %lu s (%08lx) \r\n", total_power_on, total_power_on);
// ESP_LOGD(text);
// sprintf(text, "%d days, %d years\r\n", days, years);
// ESP_LOGD(text);
}
float PMBus::readFanCommand()
{
fanSpeed = read_linear(FAN_COMMAND_1);
return fanSpeed;
}
/*
* Copyright (c) 2024 Tomosawa
* https://github.com/Tomosawa/
* All rights reserved
*/
#ifndef PMBUS_H
#define PMBUS_H
#include <Arduino.h>
#include <Wire.h>
#include <time.h>
#define STATUS_REGISTERS 10
// I2C通讯频率
#define I2C_PMBUS_CLOCK 100000
// 与电源PMBus通讯类
class PMBus
{
public:
PMBus();
int init();
int scan();
void clear_faults();
void off();
void on();
bool checkOnOffState();
bool checkDeviceOnline();
void getRunTime();
void recordTurnOnTime();
float readFanCommand();
void readMFR(); // 读取电源厂商信息
String mfr_id, mfr_model, mfr_revision, mfr_location, mfr_date, mfr_serial;
float V_in = 0.0, I_in = 0.0, V_out = 0.0, I_out = 0.0, T[3] = {0.0, 0.0, 0.0}, fan[2] = {0.0, 0.0},
W_in = 0.0, W_out = 0.0, fanSpeed = 0.0, E_in = 0.0, E_out = 0.0;
uint8_t pmbus_revision = 0, vout_mode = 0;
uint8_t status_u8 = 0, status_vout = 0, status_iout = 0, status_input = 0, status_temperature = 0,
status_cml = 0, status_other = 0, status_mfr_specific = 0, status_fans = 0, *status_byte[STATUS_REGISTERS];
uint16_t status_word = 0, vout_command = 0;
long turn_on_time = 0, total_power_on = 0;
typedef struct linear
{
int y : 11;
int n : 5;
} linear_t;
typedef union
{
linear_t linear;
uint16_t u16;
} UniLinear;
typedef struct Coefficient
{
uint16_t m;
uint16_t b;
uint16_t R;
} Coefficient_t;
private:
uint8_t read_byte(uint8_t reg);
void write_byte(uint8_t reg, uint8_t value);
uint16_t read_word(uint8_t reg);
void write_word(uint8_t reg, uint16_t value);
String read_string(uint8_t reg);
void read_block(uint8_t reg, int bytes, uint8_t *buffer);
float read_linear(uint8_t reg);
void write_linear(uint8_t reg, float value);
float read_linear16(uint8_t reg);
float read_direct(uint8_t reg);
void readCoefficients(uint8_t reg, Coefficient_t *coeff);
float linear2float(uint16_t u16);
float linear11ToFloat(uint16_t data);
float ulinear16ToFloat(uint16_t data);
int8_t readVoutMode(uint8_t reg);
uint16_t float2linear(float value);
uint16_t convertlinear11(uint16_t value);
float readVout(uint8_t reg);
bool GetVOutFormat();
uint16_t convertHex2Dec(uint16_t hexData);
private:
bool bReadMFR = false; // 是否读取了厂商信息了
int8_t exponent = 0;// uLinear16计算用
bool isVOutLinear = true;// 输出电压的格式
Coefficient_t coeff;
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment