forked from esphome/esphome
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
178 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
#include "vaillantx6.h" | ||
Check failure on line 1 in esphome/components/vaillantx6/vaillantx6.cpp GitHub Actions / Run script/ci-custom
Check failure on line 1 in esphome/components/vaillantx6/vaillantx6.cpp GitHub Actions / Run script/ci-custom
|
||
|
||
void logCmd(const char *tag, byte *cmd) { | ||
ESP_LOGD("Vaillantx6", "%s: 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x", tag, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]); | ||
} | ||
|
||
uint8_t VaillantReturnTypeLength(VaillantReturnTypes t) { | ||
switch (t) { | ||
case SensorState: | ||
case Bool: | ||
case Minutes: | ||
return 1; | ||
case Temperature: | ||
return 2; | ||
default: | ||
return 0; | ||
} | ||
} | ||
|
||
float VaillantParseTemperature(byte *answerBuff, uint8_t offset) { | ||
int16_t i = (answerBuff[offset] << 8) | answerBuff[offset + 1]; | ||
return i / (16.0f); | ||
} | ||
|
||
int VaillantParseBool(byte *answerBuff, uint8_t offset) { | ||
switch (answerBuff[offset]) { | ||
case 0xF0: | ||
case 0x00: | ||
return 0; | ||
case 0x0F: | ||
case 0x01: | ||
return 1; | ||
default: | ||
ESP_LOGE("VaillantParseBool", "Unable to parse a bool from 0x%.2x", answerBuff[offset]); | ||
return -1; | ||
} | ||
} | ||
|
||
const VaillantCommand vaillantCommands[] = { | ||
{"Vorlauf Ist", 0x18, Temperature}, | ||
{"Aussen Temperatur", 0x6A, Temperature}, | ||
{"Vorlauf Soll", 0x39, Temperature}, | ||
{"Vorlauf 789 Soll", 0x25, Temperature}, | ||
{"Rücklauf Ist", 0x98, Temperature}, | ||
{"Speicher Ist", 0x17, Temperature}, | ||
{"Speicher Soll", 0x04, Temperature}, | ||
{"Brauchwasser Ist", 0x16, Temperature}, | ||
{"Brauchwasser Soll", 0x01, Temperature}, | ||
{"Drehzahl Soll", 0x24, Temperature}, | ||
{"Drehzahl Ist", 0x83, Temperature}, | ||
{"Brenner", 0x0d, Bool}, | ||
{"Winter", 0x08, Bool}, | ||
{"Pumpe", 0x44, Bool}, | ||
{"Flammsignal", 0x05, Bool}, | ||
{"Gasmagnetventil", 0x48, Bool}, | ||
{"Zünder", 0x49, Bool}, | ||
{"Verbliebene Brennsperrzeit", 0x38, Minutes}, | ||
}; | ||
|
||
const byte vaillantCommandsSize = sizeof(vaillantCommands) / sizeof *(vaillantCommands); | ||
|
||
Vaillantx6Sensor::Vaillantx6Sensor(UARTComponent *parent, const VaillantCommand *command, uint32_t update_interval) | ||
: PollingComponent(update_interval), UARTDevice(parent), command_(command) {} | ||
|
||
void Vaillantx6Sensor::set_sensor(Sensor *sensor) { | ||
sensor_ = sensor; | ||
} | ||
|
||
void Vaillantx6Sensor::set_binary_sensor(BinarySensor *binary_sensor) { | ||
binary_sensor_ = binary_sensor; | ||
} | ||
|
||
byte Vaillantx6Sensor::checksum(byte *data, byte len) { | ||
byte checksum = 0; | ||
for (byte i = 0; i < len; i++) { | ||
if (checksum & 0x80) { | ||
checksum = (checksum << 1) | 1; | ||
checksum = checksum ^ 0x18; | ||
} else { | ||
checksum = checksum << 1; | ||
} | ||
checksum = checksum ^ data[i]; | ||
} | ||
return checksum; | ||
} | ||
|
||
bool Vaillantx6Sensor::checksumOk(byte *answerBuff, byte len) { | ||
logCmd("Answer", answerBuff); | ||
return checksum(answerBuff, len - 1) == answerBuff[len - 1]; | ||
} | ||
|
||
int Vaillantx6Sensor::buildPacket(byte *packet, byte address) { | ||
const byte startBytes[4] = {0x07, 0x00, 0x00, 0x00}; | ||
int i = 0; | ||
while (i < sizeof(startBytes)) { | ||
packet[i] = startBytes[i]; | ||
i++; | ||
} | ||
packet[i] = address; | ||
i++; | ||
packet[i] = 0x00; | ||
i++; | ||
packet[i] = checksum(packet, 6); | ||
return i; | ||
} | ||
|
||
int Vaillantx6Sensor::sendPacket(byte *answerBuff, byte *packet) { | ||
int answerLen = 0; | ||
int readRetry = 3; | ||
write_array(packet, CMD_LENGTH); | ||
|
||
while (available() < 1) { | ||
delay(50); | ||
Check failure on line 113 in esphome/components/vaillantx6/vaillantx6.cpp GitHub Actions / Run script/ci-custom
|
||
readRetry--; | ||
if (readRetry < 0) { | ||
ESP_LOGE("Vaillantx6 sendPacket", "Timed out waiting for bytes from Vaillant"); | ||
return -3; | ||
} | ||
} | ||
answerLen = peek(); | ||
|
||
if (answerLen > ANSWER_LENGTH) { | ||
ESP_LOGE("Vaillantx6 sendPacket", "Received an answer of unexpected length %d, ignoring", answerLen); | ||
while (available()) { | ||
read(); | ||
} | ||
return -1; | ||
} | ||
read_array(answerBuff, answerLen); | ||
if (!checksumOk(answerBuff, answerLen)) { | ||
ESP_LOGE("Vaillantx6 sendPacket", "Packet has invalid checksum"); | ||
while (available()) { | ||
read(); | ||
} | ||
return -2; | ||
} | ||
return answerLen; | ||
} | ||
|
||
void Vaillantx6Sensor::update() { | ||
byte *cmdPacket = (byte *)malloc(sizeof(byte) * CMD_LENGTH); | ||
byte *answerBuff = (byte *)malloc(sizeof(byte) * ANSWER_LENGTH); | ||
|
||
buildPacket(cmdPacket, command_->Address); | ||
logCmd(command_->Name.c_str(), cmdPacket); | ||
|
||
int answerLen = sendPacket(answerBuff, cmdPacket); | ||
if (answerLen < 0) { | ||
ESP_LOGE("Vaillantx6", "sendPacket returned an error: %d", answerLen); | ||
} else if (answerLen > 3) { | ||
switch (command_->ReturnType) { | ||
case Temperature: | ||
if (sensor_ != nullptr) { | ||
float temp = VaillantParseTemperature(answerBuff, 2); | ||
sensor_->publish_state(temp); | ||
} | ||
break; | ||
case Bool: | ||
if (binary_sensor_ != nullptr) { | ||
int b = VaillantParseBool(answerBuff, 2); | ||
if (b >= 0) { | ||
binary_sensor_->publish_state(b); | ||
} | ||
} | ||
break; | ||
case Minutes: | ||
if (sensor_ != nullptr) { | ||
sensor_->publish_state(answerBuff[2]); | ||
} | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
free(cmdPacket); | ||
free(answerBuff); | ||
} |