├── CSPS ├── KCORES_CSPS.cpp ├── KCORES_CSPS.h └── main.hpp ├── README.md └── csps_esphome.yaml /CSPS/KCORES_CSPS.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file KCORES_CSPS.cpp 3 | * 4 | * This is a library for the CSPS PMBUS 5 | * Written by AlphaArea 6 | * 7 | * GPL license, all text here must be included in any redistribution. 8 | * 9 | */ 10 | 11 | #include "KCORES_CSPS.h" 12 | 13 | CSPS::CSPS(byte CSPS_addr) 14 | { 15 | _CSPS_addr = CSPS_addr; 16 | _ROM_addr = CSPS_addr - 8; 17 | _CSPS_READ_CHECKSUM = false; 18 | Wire.begin(); 19 | } 20 | 21 | CSPS::CSPS(byte CSPS_addr, byte ROM_addr) 22 | { 23 | _CSPS_addr = CSPS_addr; 24 | _ROM_addr = ROM_addr; 25 | _CSPS_READ_CHECKSUM = false; 26 | Wire.begin(); 27 | } 28 | 29 | 30 | CSPS::CSPS(byte CSPS_addr, byte ROM_addr, bool ENABLE_CHECKSUM) 31 | { 32 | _CSPS_addr = CSPS_addr; 33 | _ROM_addr = ROM_addr; 34 | _CSPS_READ_CHECKSUM = ENABLE_CHECKSUM; 35 | Wire.begin(); 36 | } 37 | 38 | String CSPS::getROM(byte addr, byte len) 39 | { 40 | String rec; 41 | for (byte n = 0; n < len; n++) 42 | rec.concat((char)readROM(addr + n)); 43 | return rec; 44 | } 45 | 46 | byte CSPS::readROM(byte dataAddr) 47 | { 48 | byte rec = 0x00; 49 | Wire.beginTransmission(_ROM_addr); 50 | Wire.write(dataAddr); 51 | Wire.endTransmission(); 52 | Wire.requestFrom(_ROM_addr, 1); 53 | if (Wire.available()) 54 | rec = Wire.read(); 55 | return rec; 56 | } 57 | 58 | // Calclate checksum read from PM BUS 59 | uint8_t checksum(uint32_t data) { 60 | uint8_t cs = 0; 61 | cs += ((data & 0xFF0000) >> 16); 62 | cs += ((data & 0xFF00) >> 8); 63 | cs += (data & 0xFF); 64 | 65 | cs = ((0xFF - cs) + 1) & 0xFF; 66 | return cs; 67 | } 68 | 69 | uint32_t CSPS::readCSPSword(byte dataAddr) 70 | { 71 | byte regCS = ((0xFF - (dataAddr + (_CSPS_addr << 1))) + 1) & 0xFF; 72 | uint32_t rec = 0xFFFF; 73 | Wire.beginTransmission(_CSPS_addr); 74 | Wire.write(dataAddr); 75 | Wire.write(regCS); 76 | Wire.endTransmission(); 77 | Wire.requestFrom(_CSPS_addr, 3); 78 | if (Wire.available()) 79 | { 80 | rec = Wire.read(); 81 | rec |= Wire.read() << 8; 82 | rec |= Wire.read() << 16; 83 | 84 | if (_CSPS_READ_CHECKSUM) { 85 | uint8_t cs = checksum(rec); 86 | 87 | if (cs != 0) { 88 | // Output error to serial 89 | if (Serial) { 90 | Serial.printf("CSPS::readCSPSword() Missmatch checksum. addr: 0x%02x, chk: 0x%02x\n", dataAddr, cs); 91 | } 92 | } 93 | 94 | // Don't return checksum 95 | return rec & 0x00FFFF; 96 | } 97 | return rec; 98 | } 99 | else 100 | return 0; 101 | } 102 | 103 | void CSPS::writeCSPSword(byte dataAddr, unsigned int data) 104 | { 105 | byte valLSB = lowByte(data), 106 | valMSB = highByte(data); 107 | uint8_t cs = (_CSPS_addr << 1) + dataAddr + valLSB + valMSB; 108 | uint8_t regCS = ((0xFF - cs) + 1) & 0xff; 109 | //the checksum is the 'secret sauce' 110 | //writeInts = [reg, valLSB, valMSB, regCS]; //write these 4 bytes to i2c 111 | Wire.beginTransmission(_CSPS_addr); 112 | Wire.write(dataAddr); 113 | Wire.write(valLSB); 114 | Wire.write(valMSB); 115 | Wire.write(regCS); 116 | Wire.endTransmission(); 117 | } 118 | -------------------------------------------------------------------------------- /CSPS/KCORES_CSPS.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file KCORES_CSPS.h 3 | * 4 | * This is a library for the CSPS PMBUS 5 | * Written by AlphaArea 6 | * 7 | * GPL license, all text here must be included in any redistribution. 8 | * 9 | */ 10 | 11 | #ifndef KCORES_CSPS_H 12 | #define KCORES_CSPS_H 13 | 14 | #include 15 | #include 16 | 17 | class CSPS 18 | { 19 | public: 20 | CSPS(byte CSPS_addr); 21 | CSPS(byte CSPS_addr, byte ROM_addr); 22 | CSPS(byte CSPS_addr, byte ROM_addr, bool ENABLE_CHECKSUM); 23 | 24 | String getROM(byte addr, byte len); 25 | 26 | //Spare Part No 27 | String getSPN() 28 | { 29 | return getROM(0x12, 0x0A); 30 | }; 31 | 32 | //Manufacture Date 33 | String getMFG() 34 | { 35 | return getROM(0x1D, 0x08); 36 | }; 37 | 38 | //Manufacturer 39 | String getMFR() 40 | { 41 | return getROM(0x2C, 0x05); 42 | }; 43 | 44 | //Power Name 45 | String getName() 46 | { 47 | return getROM(0x32, 0x1A); 48 | }; 49 | 50 | //Option Kit No 51 | String getOKN() 52 | { 53 | return getROM(0x4D, 0x0A); 54 | }; 55 | 56 | //CT Date Codes 57 | String getCT() 58 | { 59 | return getROM(0x5B, 0x0E); 60 | }; 61 | 62 | float getInputVoltage() 63 | { 64 | return (float)readCSPSword(0x08) / 32; 65 | }; 66 | 67 | float getInputCurrent() 68 | { 69 | return (float)readCSPSword(0x0A) / 64; 70 | }; 71 | 72 | float getInputPower() 73 | { 74 | return (float)readCSPSword(0x0C); 75 | }; 76 | 77 | float getOutputVoltage() 78 | { 79 | return (float)readCSPSword(0x0E) / 256; 80 | }; 81 | 82 | float getOutputCurrent() 83 | { 84 | return (float)readCSPSword(0x10) / 64; 85 | }; 86 | 87 | float getOutputPower() 88 | { 89 | return (float)readCSPSword(0x12); 90 | }; 91 | 92 | float getTemp1() 93 | { 94 | return (float)readCSPSword(0x1A) / 64; 95 | }; 96 | 97 | float getTemp2() 98 | { 99 | return (float)readCSPSword(0x1C) / 64; 100 | }; 101 | 102 | uint16_t getFanRPM() 103 | { 104 | return readCSPSword(0x1E); 105 | }; 106 | 107 | uint32_t getRunTime() 108 | { 109 | return readCSPSword(0x30); 110 | }; 111 | 112 | void setFanRPM(uint16_t rpm) 113 | { 114 | writeCSPSword(0x40, rpm); 115 | }; 116 | 117 | private: 118 | bool _CSPS_READ_CHECKSUM; 119 | byte _CSPS_addr; 120 | byte _ROM_addr; 121 | byte readROM(byte dataAddr); 122 | 123 | uint32_t readCSPSword(byte dataAddr); 124 | void writeCSPSword(byte dataAddr, unsigned int data); 125 | }; 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /CSPS/main.hpp: -------------------------------------------------------------------------------- 1 | #include "KCORES_CSPS.h" 2 | #include "esphome.h" 3 | 4 | CSPS PowerSupply(0x5E, 0x56, true); 5 | 6 | class CSPSPower : public PollingComponent { 7 | public: 8 | TextSensor *name = new TextSensor(); 9 | TextSensor *ct = new TextSensor(); 10 | 11 | Sensor *fan_speed = new Sensor(); 12 | Sensor *temp1 = new Sensor(); 13 | Sensor *temp2 = new Sensor(); 14 | Sensor *power_in = new Sensor(); 15 | Sensor *power_out = new Sensor(); 16 | Sensor *current_out = new Sensor(); 17 | Sensor *current_in = new Sensor(); 18 | Sensor *voltage_out = new Sensor(); 19 | Sensor *voltage_in = new Sensor(); 20 | 21 | CSPSPower(): PollingComponent(15000) { } 22 | 23 | void setup() override { 24 | Wire.setClock(10000); 25 | 26 | ESP_LOGD("Power Supply", "Spare Part No: %s", PowerSupply.getSPN().c_str()); 27 | ESP_LOGD("Power Supply", "Manufacture Date: %s", PowerSupply.getMFG().c_str()); 28 | ESP_LOGD("Power Supply", "Manufacturer: %s", PowerSupply.getMFR().c_str()); 29 | ESP_LOGD("Power Supply", "Power Name: %s", PowerSupply.getName().c_str()); 30 | ESP_LOGD("Power Supply", "Option Kit No: %s", PowerSupply.getOKN().c_str()); 31 | ESP_LOGD("Power Supply", "CT Date Codes: %s", PowerSupply.getCT().c_str()); 32 | } 33 | 34 | void update() override { 35 | name->publish_state(PowerSupply.getName().c_str()); 36 | ct->publish_state(PowerSupply.getCT().c_str()); 37 | 38 | fan_speed->publish_state(PowerSupply.getFanRPM()); 39 | temp1->publish_state(PowerSupply.getTemp1()); 40 | temp2->publish_state(PowerSupply.getTemp2()); 41 | power_out->publish_state(PowerSupply.getOutputPower()); 42 | power_in->publish_state(PowerSupply.getInputPower()); 43 | current_out->publish_state(PowerSupply.getOutputCurrent()); 44 | current_in->publish_state(PowerSupply.getInputCurrent()); 45 | voltage_out->publish_state(PowerSupply.getOutputVoltage()); 46 | voltage_in->publish_state(PowerSupply.getInputVoltage()); 47 | } 48 | 49 | void set_fan_rpm(float state) { 50 | PowerSupply.setFanRPM(state); 51 | } 52 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # csps_esphome 2 | CSPS Power Supply PMBUS For ESPHome 3 | 4 | 通过ESPHome的自定义I2C读取CSPS电源的PMBUS传感器、控制CSPS风扇转速。 5 | 支持华为、HP、联想系列CSPS电源。 6 | 代码用NODEMCU测试过。其他ESP板子没测。 7 | -------------------------------------------------------------------------------- /csps_esphome.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: nodetest1 3 | includes: 4 | - CSPS/main.hpp 5 | - CSPS/KCORES_CSPS.h 6 | - CSPS/KCORES_CSPS.cpp 7 | 8 | libraries: 9 | - "Wire" 10 | 11 | esp8266: 12 | board: nodemcuv2 13 | 14 | # Enable logging 15 | logger: 16 | 17 | # Enable Home Assistant API 18 | api: 19 | password: 'API密码' 20 | 21 | ota: 22 | password: "OTAMIM" 23 | 24 | web_server: 25 | port: 80 26 | 27 | wifi: 28 | networks: 29 | - ssid: "WIFI信号1" 30 | password: "WIFI密码" 31 | - ssid: "WIFI信号2" 32 | password: "WIFI密码" 33 | 34 | # Enable fallback hotspot (captive portal) in case wifi connection fails 35 | ap: 36 | ssid: "热点" 37 | password: "热点密码" 38 | 39 | captive_portal: 40 | 41 | time: 42 | - platform: sntp 43 | id: nodetest1_time 44 | servers: 45 | - ntp1.aliyun.com 46 | - ntp.aliyun.com 47 | - cn.pool.ntp.org 48 | 49 | i2c: 50 | sda: D5 51 | scl: D6 52 | scan: true 53 | id: bus_a 54 | 55 | number: 56 | - platform: template 57 | id: csps_rpm 58 | name: "Power Fan RPM" 59 | optimistic: true 60 | min_value: 0 61 | max_value: 20000 62 | step: 500 63 | on_value: 64 | then: 65 | - lambda: |- 66 | auto power = new CSPSPower(); 67 | App.register_component(power); 68 | power->set_fan_rpm(id(csps_rpm).state); 69 | 70 | text_sensor: 71 | - platform: custom 72 | lambda: |- 73 | auto power = new CSPSPower(); 74 | App.register_component(power); 75 | return {power->name,power->ct}; 76 | 77 | text_sensors: 78 | - name: "Power Name" 79 | - name: "CT Code" 80 | 81 | sensor: 82 | - platform: wifi_signal 83 | name: "WiFi Signal Sensor" 84 | update_interval: 60s 85 | 86 | - platform: custom 87 | lambda: |- 88 | auto power = new CSPSPower(); 89 | App.register_component(power); 90 | return {power->fan_speed, power->temp1, power->temp2, power->power_out, power->power_in, power->current_out, power->current_in, power->voltage_out, power->voltage_in}; 91 | 92 | sensors: 93 | - name: "Fan Speed" 94 | accuracy_decimals: 0 95 | unit_of_measurement: RPM 96 | - name: "Temp 1" 97 | accuracy_decimals: 1 98 | unit_of_measurement: °C 99 | - name: "Temp 2" 100 | accuracy_decimals: 1 101 | unit_of_measurement: °C 102 | - name: "Power Out" 103 | accuracy_decimals: 0 104 | unit_of_measurement: W 105 | - name: "Power In" 106 | accuracy_decimals: 0 107 | unit_of_measurement: W 108 | - name: "Current Out" 109 | accuracy_decimals: 1 110 | unit_of_measurement: A 111 | - name: "Current In" 112 | accuracy_decimals: 1 113 | unit_of_measurement: A 114 | - name: "Voltage Out" 115 | accuracy_decimals: 1 116 | unit_of_measurement: V 117 | - name: "Voltage In" 118 | accuracy_decimals: 1 119 | unit_of_measurement: V --------------------------------------------------------------------------------