Closed jensgraef closed 1 year ago
@jensgraef We need that e.g. for this:
{ LPWW , true, false, SensorType::INT, 0, "Ladepumpe", "", NULL }, // ["aus", "Ladepumpe", "Warmwasserpumpe", "beide"]
There we need to create two binary sensors out of it:
BIN 00 DEC 0 = Beide aus
BIN 01 DEC 1 = Ladepumpe an
BIN 10 DEC 2 = Zirkulationspumpe an
DIN 11 DEC 3 = Ladepumpe und Zirkulationspumpe an
actually this telegram is mapped to a binary sensor so only the first bit is processed (Ladepumpe an/aus).
Do you see any way to do that with the existing code?
This is the water heater of the Buderus:
As you can see there must be something wrong with it because it is losing temperature quiet fast... 15°C in 2,6 hours !?!? That is why I want so see the circulation that is behind the other "bit" --> Zirkulationspumpe :-) ...
With the current code you could map it to a numeric sensor and do the remaining work in home assistant, e.g. with an automation that toggles two switches depending on the value of the number.
I've got a rough idea how to do it in the km217 module, but it's not yet full thought true:
I wont have much time until next week, so it might take some time to build this.
@jensgraef you name it, it is really crap to implement inside an ESPhome component.
Yes, this is how modbus controller has done it.
Maybe this could help (I don't understand it completely but it seems to follow a lot of @jensgraef points... )
https://esphome.io/components/modbus_controller.html --> Section bitmask in the documentation
Code:
https://github.com/esphome/esphome/blob/dev/esphome/components/modbus_controller/modbus_controller.h
--> template
Maybe we could do the same with the address and byte that has so be read?
So maybe something like this could be very flexibly, because everybody can "select" anything via his yaml code without changing the source / adding something to the source:
binary_sensor:
- platform: km271_wifi
id: some_sensor_id
name: "Zirkulationspumpe"
address: 0x8429
byte: 1
bitmask: 0x2 #bit 1
- platform: km271_wifi
id: some_sensor_id
name: "Ladepumpe"
address: 0x8429
byte: 1 # first byte after the address
bitmask: 0x1 #bit 0
- platform: km271_wifi
id: some_sensor_id
name: "Absenkung_Solar"
address: 0x8429
byte: 1 # first byte after the address
bitmask: 0x2 #bit 2
same "style" for sensors:
- platform: km271_wifi
id: raumsolltemperatur_hk1
name: "Raumsolltemperatur HK1"
address: 0x8004
byte: 1 # first byte after the address
unit_of_measurement: "°c"
device_class: "temperature"
state_class: "measurement"
value_type: U_INT_DIV2
accuracy_decimals: 1
This way we could even read the config variables to sensors:
- platform: km271_wifi
id: tagtemperatur_hk1
name: "Tagtemperatur_HK1"
address: 0x0000
byte: 3 # third byte after the address
unit_of_measurement: "°c"
device_class: "temperature"
state_class: "measurement"
value_type: U_INT # unsigned integer
accuracy_decimals: 1
It would be more generic and will need longer yaml code but you would be very flexible with the yaml without changing anything to the c++ code...
select entites could go from:
select:
- platform: template
name: "Warmwasser Betriebsart"
id: warmwasser_betriebsart
entity_category: config
optimistic: true
options:
- Dauerhaft aus (0)
- Dauerhaft ein (1)
- Automatik (2)
initial_option: Automatik (2)
set_action:
- lambda:
auto index = id(warmwasser_betriebsart).index_of(x);
if (index.has_value()) {
uint8_t command[] = {0x0C, 0x0E, (uint8_t)index.value(), 0x65, 0x65, 0x65, 0x65, 0x65};
budoil->writer.enqueueTelegram(command, 8);
}
to:
select:
- platform: km271_wifi
name: "Warmwasser Betriebsart"
id: warmwasser_betriebsart
entity_category: config
address: 0x0C0E
byte: 1 # first byte after the address
optionsmap:
"Dauerhaft aus (0)": 0
"Dauerhaft ein (1)": 1
"Automatik (2)": 2
"Three": 3
as to: https://esphome.io/components/select/modbus_controller.html
number would be like sensor and switch like binary sensor
@Bascht74 If you like you can check out the branch support-single-bit-sensors
and check if it works as expected.
If someone wants to create a pull request for splitting all the other sensors (e.g. boiler error), feel free to do so.
I extended km271.h and km271_params.h with more single-bit entities, if its ok i move on with binaray_sensor.py and buderus-km271.yaml
km271.h#
#pragma once
#include <string>
#include <vector>
#include <chrono>
#include <iostream>
#include <sys/time.h>
#include <ctime>
#include "3964r.h"
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/uart/uart.h"
#include "km271_params.h"
#define GENERATE_SENSOR_SETTER(key, parameterId, sensorTypeParam) void set_##key##_sensor(esphome::sensor::Sensor *sensor) \
{ set_sensor(parameterId, sensorTypeParam, sensor); }
#define GENERATE_BINARY_SENSOR_SETTER(key, parameterId, sensorTypeParam) void set_##key##_binary_sensor(esphome::binary_sensor::BinarySensor *sensor) \
{ set_binary_sensor(parameterId, sensorTypeParam, sensor); }
#define GENERATE_SWITCH_SETTER(key, parameterId, sensorTypeParam) void set_##key##_switch(BuderusParamSwitch *switch_) \
{ set_switch(parameterId, sensorTypeParam, switch_); }
#define GENERATE_NUMBER_SETTER(key, parameterId, sensorTypeParam) void set_##key##_number(BuderusParamNumber *number) \
{ set_number(parameterId, sensorTypeParam, number); }
namespace esphome {
namespace KM271 {
class KM271Component : public Component, public uart::UARTDevice {
public:
KM271Component();
void loop() override;
void dump_config() override;
// Betriebswerte 1 HK1
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_switch_off_optimization, BW1HK1, 0);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_switch_on_optimization, BW1HK1, 1);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_automatic, BW1HK1, 2);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_ww_priority_processing, BW1HK1, 3);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_screed_drying, BW1HK1, 4);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_holiday, BW1HK1, 5);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_antifreeze, BW1HK1, 6);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_manually, BW1HK1, 7);
// Betriebswerte 2 HK1
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_summer, BW2HK1, 0);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_day, BW2HK1, 1);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_no_comm_with_rc, BW2HK1, 2);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_rc_faulty, BW2HK1, 3);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_flow_sensor_error, BW2HK1, 4);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_max_flow, BW2HK1, 5);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_external_fault_input, BW2HK1, 6);
// GENERATE_BINARY_SENSOR_SETTER(heating_circuit_1_party_pause, BW2HK1, 7);
GENERATE_SENSOR_SETTER(heating_circuit_1_flow_target_temperature, VSTHK1, 0);
GENERATE_SENSOR_SETTER(heating_circuit_1_flow_temperature, VITHK1, 0);
GENERATE_SENSOR_SETTER(heating_circuit_1_room_target_temperature, RSTHK1, 0);
GENERATE_SENSOR_SETTER(heating_circuit_1_room_temperature, RITHK1, 0);
GENERATE_SENSOR_SETTER(heating_circuit_1_pump_power, PLHK1, 0);
GENERATE_SENSOR_SETTER(heating_circuit_1_mixer_position, MSHK1, 0);
GENERATE_SENSOR_SETTER(heating_circuit_1_curve_p10, KLHK1_P10, 0);
GENERATE_SENSOR_SETTER(heating_circuit_1_curve_0, KLHK1_P00, 0);
GENERATE_SENSOR_SETTER(heating_circuit_1_curve_n10, KLHK1_N10, 0);
// Betriebswerte 1 HK2
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_switch_off_optimization, BW1HK2, 0);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_switch_on_optimization, BW1HK2, 1);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_automatic, BW1HK2, 2);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_ww_priority_processing, BW1HK2, 3);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_screed_drying, BW1HK2, 4);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_holiday, BW1HK2, 5);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_antifreeze, BW1HK2, 6);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_manually, BW1HK2, 7);
// Betriebswerte 2 HK2
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_summer, BW2HK2, 0);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_day, BW2HK2, 1);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_no_comm_with_rc, BW2HK2, 2);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_rc_faulty, BW2HK2, 3);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_flow_sensor_error, BW2HK2, 4);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_max_flow, BW2HK2, 5);
GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_external_fault_input, BW2HK2, 6);
//GENERATE_BINARY_SENSOR_SETTER(heating_circuit_2_party_pause, BW2HK2, 7);
GENERATE_SENSOR_SETTER(heating_circuit_2_flow_target_temperature, VSTHK2, 0);
GENERATE_SENSOR_SETTER(heating_circuit_2_flow_temperature, VITHK2, 0);
GENERATE_SENSOR_SETTER(heating_circuit_2_room_target_temperature, RSTHK2, 0);
GENERATE_SENSOR_SETTER(heating_circuit_2_room_temperature, RITHK2, 0);
GENERATE_SENSOR_SETTER(heating_circuit_2_pump_power, PLHK2, 0);
GENERATE_SENSOR_SETTER(heating_circuit_2_mixer_position, MSHK2, 0);
GENERATE_SENSOR_SETTER(heating_circuit_2_curve_p10, KLHK2_P10, 0);
GENERATE_SENSOR_SETTER(heating_circuit_2_curve_0, KLHK2_P00, 0);
GENERATE_SENSOR_SETTER(heating_circuit_2_curve_n10, KLHK2_N10, 0);
// Betriebswerte 1 WW
GENERATE_BINARY_SENSOR_SETTER(ww_automatic, BW1WW, 0);
GENERATE_BINARY_SENSOR_SETTER(ww_disinfection, BW1WW, 1);
GENERATE_BINARY_SENSOR_SETTER(ww_reload, BW1WW, 2);
GENERATE_BINARY_SENSOR_SETTER(ww_holiday, BW1WW, 3);
GENERATE_BINARY_SENSOR_SETTER(ww_error_disinfection, BW1WW, 4);
GENERATE_BINARY_SENSOR_SETTER(ww_error_sensor, BW1WW, 5);
GENERATE_BINARY_SENSOR_SETTER(ww_error_stays_cold, BW1WW, 6);
GENERATE_BINARY_SENSOR_SETTER(ww_error_anode, BW1WW, 7);
// Betriebswerte 2 WW
GENERATE_BINARY_SENSOR_SETTER(ww_loading, BW2WW, 0);
GENERATE_BINARY_SENSOR_SETTER(ww_manually, BW2WW, 1);
GENERATE_BINARY_SENSOR_SETTER(ww_reloading, BW2WW, 2);
GENERATE_BINARY_SENSOR_SETTER(ww_switch_off_optimization, BW2WW, 3);
GENERATE_BINARY_SENSOR_SETTER(ww_switch_on_optimization, BW2WW, 4);
GENERATE_BINARY_SENSOR_SETTER(ww_day_mode, BW2WW, 5);
GENERATE_BINARY_SENSOR_SETTER(ww_post_processing, BW2WW, 6);
GENERATE_BINARY_SENSOR_SETTER(ww_priority_processing, BW2WW, 7);
GENERATE_SENSOR_SETTER(ww_target_temperature, WWST, 0);
GENERATE_SENSOR_SETTER(ww_temperature, WWIT, 0);
GENERATE_SENSOR_SETTER(boiler_target_temperature, KVST, 0);
GENERATE_SENSOR_SETTER(boiler_temperature, KVIT, 0);
GENERATE_SENSOR_SETTER(boiler_turn_on_temperature, BET, 0);
GENERATE_SENSOR_SETTER(boiler_turn_off_temperature, BAT, 0);
GENERATE_SENSOR_SETTER(exhaust_gas_temperature, ABTMP, 0);
GENERATE_SENSOR_SETTER(outdoor_temperature, AT, 0);
GENERATE_SENSOR_SETTER(attenuated_outdoor_temperature, ATD, 0);
// Pumpenansteuerung
GENERATE_BINARY_SENSOR_SETTER(load_pump_running, LPWW, 0);
GENERATE_BINARY_SENSOR_SETTER(circulation_pump_running, LPWW, 1);
GENERATE_BINARY_SENSOR_SETTER(solar_pump_lowering, LPWW, 2);
// Kesselfehler
GENERATE_BINARY_SENSOR_SETTER(error_burner_malfunction, KFEHL, 0);
GENERATE_BINARY_SENSOR_SETTER(error_boiler_sensor, KFEHL, 1);
GENERATE_BINARY_SENSOR_SETTER(error_additional_sensor, KFEHL, 2);
GENERATE_BINARY_SENSOR_SETTER(error_boiler_stays_cold, KFEHL, 3);
GENERATE_BINARY_SENSOR_SETTER(error_exhaust_gas_sensor, KFEHL, 4);
GENERATE_BINARY_SENSOR_SETTER(error_exhaust_gas_over_limit, KFEHL, 5);
GENERATE_BINARY_SENSOR_SETTER(error_safety_chain_released, KFEHL, 6);
GENERATE_BINARY_SENSOR_SETTER(error_external_disturbance, KFEHL, 7);
// Kesselbetrieb
GENERATE_BINARY_SENSOR_SETTER(boiler_emission_test, KBETR, 0);
GENERATE_BINARY_SENSOR_SETTER(boiler_1st_stage_operation, KBETR, 1);
GENERATE_BINARY_SENSOR_SETTER(boiler_protection, KBETR, 2);
GENERATE_BINARY_SENSOR_SETTER(boiler_under_operation, KBETR, 3);
GENERATE_BINARY_SENSOR_SETTER(boiler_performance_free, KBETR, 4);
GENERATE_BINARY_SENSOR_SETTER(boiler_performance_high, KBETR, 5);
GENERATE_BINARY_SENSOR_SETTER(boiler_2st_stage_operation, KBETR, 6);
GENERATE_BINARY_SENSOR_SETTER(boiler_actuation, BANST, 0);
GENERATE_SWITCH_SETTER(ww_heating_auto_off, CFG_WW_Aufbereitung, 0);
GENERATE_NUMBER_SETTER(ww_temperature, CFG_WW_Temperatur, 3);
void setup();
float get_setup_priority() const override;
void update();
void on_shutdown();
Writer3964R writer;
protected:
const t_Buderus_R2017_ParamDesc *findParameterForNewSensor(Buderus_R2017_ParameterId parameterId, uint16_t sensorTypeParam, bool writableRequired);
void set_sensor(Buderus_R2017_ParameterId parameterId, uint16_t sensorTypeParam, esphome::sensor::Sensor *sensor);
void set_binary_sensor(Buderus_R2017_ParameterId parameterId, uint16_t sensorTypeParam, esphome::binary_sensor::BinarySensor *sensor);
void set_switch(Buderus_R2017_ParameterId parameterId, uint16_t sensorTypeParam, BuderusParamSwitch *switch_);
void set_number(Buderus_R2017_ParameterId parameterId, uint16_t sensorTypeParam, BuderusParamNumber *number);
void process_incoming_byte(uint8_t c);
void parse_buderus(uint8_t * buf, size_t len);
// Helper function (for better readability of code)
void send_ACK_DLE();
void send_NAK();
void writeRequestValues();
size_t genDataString(char* outbuf, uint8_t* inbuf, size_t len);
void print_hex_buffer(uint8_t* buf, size_t len);
uint32_t last_received_byte_time;
Parser3964R parser;
/** used to call the loop function of the sensors every x calls to the loop function of the component */
uint8_t sensorLoopCounter;
};
} // namespace KM271
} // namespace esphome
km271_params.h
#pragma once
#include <string>
#include <vector>
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/switch/switch.h"
#include "esphome/components/number/number.h"
#include <unordered_map>
namespace esphome {
namespace KM271 {
enum Buderus_R2017_ParameterId {
CFG_WW_Temperatur = 0x007e,
CFG_WW_Aufbereitung = 0x0085,
BW1HK1 = 0x8000, //: "Betriebswerte 1 HK1"
BW2HK1 = 0x8001, //: "Betriebswerte 2 HK1"
VSTHK1 = 0x8002, //: "Vorlaufsolltemperatur HK1" (Grad)
VITHK1 = 0x8003, //: "Vorlaufisttemperatur HK1" (Grad)
RSTHK1 = 0x8004, //: "Raumsolltemperatur HK1" (Grad)
RITHK1 = 0x8005, //: "Raumisttemperatur HK1" (Grad)
EOZHK1 = 0x8006, //: "Einschaltoptimierungszeit HK1"
AOZHK1 = 0x8007, //: "Ausschaltoptimierungszeit HK1"
PLHK1 = 0x8008, //: "Pumpenleistung HK1" (Prozent)
MSHK1 = 0x8009, //: "Mischerstellung HK1" (Prozent)
NB01 = 0x800a, //: "nicht belegt"
NB02 = 0x800b, //: "nicht belegt"
KLHK1_P10 = 0x800c, //: "Heizkennlinie HK1 bei + 10 Grad" (Grad)
KLHK1_P00 = 0x800d, //: "Heizkennlinie HK1 bei 0 Grad" (Grad)
KLHK1_N10 = 0x800e, //: "Heizkennlinie HK1 bei - 10 Grad" (Grad)
NB03 = 0x800f, //: "nicht belegt"
NB04 = 0x8010, //: "nicht belegt"
NB05 = 0x8011, //: "nicht belegt"
BW1HK2 = 0x8112, //: "Betriebswerte 1 HK2"
BW2HK2 = 0x8113, //: "Betriebswerte 2 HK2"
VSTHK2 = 0x8114, //: "Vorlaufsolltemperatur HK2" (Grad)
VITHK2 = 0x8115, //: "Vorlaufisttemperatur HK2" (Grad)
RSTHK2 = 0x8116, //: "Raumsolltemperatur HK2" (Grad)
RITHK2 = 0x8117, //: "Raumisttemperatur HK2" (Grad)
EOZHK2 = 0x8118, //: "Einschaltoptimierungszeit HK2"
AOZHK2 = 0x8119, //: "Ausschaltoptimierungszeit HK2"
PLHK2 = 0x811a, //: "Pumpenleistung HK2" (Prozent)
MSHK2 = 0x811b, //: "Mischerstellung HK2" (Prozent)
NB06 = 0x811c, //: "nicht belegt"
NB07 = 0x811d, //: "nicht belegt"
KLHK2_P10 = 0x811e, //: "Heizkennlinie HK2 bei + 10 Grad" (Grad)
KLHK2_P00 = 0x811f, //: "Heizkennlinie HK2 bei 0 Grad" (Grad)
KLHK2_N10 = 0x8120, //: "Heizkennlinie HK2 bei - 10 Grad" (Grad)
NB08 = 0x8121, //: "nicht belegt"
NB09 = 0x8122, //: "nicht belegt"
NB10 = 0x8123, //: "nicht belegt"
BW1WW = 0x8424, //: "Betriebswerte 1 WW"
BW2WW = 0x8425, //: "Betriebswerte 2 WW"
WWST = 0x8426, //: "Warmwassersolltemperatur" (Grad)
WWIT = 0x8427, //: "Warmwasseristtemperatur", (Grad)
OZWW = 0x8428, //: "Warmwasseroptimierungszeit"
LPWW = 0x8429, //: "Ladepumpe" ["aus", "Ladepumpe", "Warmwasserpumpe", "beide"]
KVST = 0x882a, //: "Kesselvorlaufsolltemperatur" (Grad)
KVIT = 0x882b, //: "Kesselvorlaufisttemperatur" (Grad)
BET = 0x882c, //: "Brennereinschalttemperatur" (Grad)
BAT = 0x882d, //: "Brennerausschalttemperatur" (Grad)
KINT1 = 0x882e, //: "Kesselintegral 1"
KINT2 = 0x882f, //: "Kesselintegral 2"
KFEHL = 0x8830, //: "Kesselfehler"
KBETR = 0x8831, //: "Kesselbetrieb"
BANST = 0x8832, //: "Brenneransteuerung" ["aus", "an"]
ABTMP = 0x8833, //: "Abgastemperatur" (Grad)
MODBSTELL = 0x8834, //: "modulare Brenner Stellwert"
NB11 = 0x8835, //: "nicht belegt"
BLZ1S2 = 0x8836, //: "Brennerlaufzeit 1 Stunden 2"
BLZ1S1 = 0x8837, //: "Brennerlaufzeit 1 Stunden 1"
BLZ1S0 = 0x8838, //: "Brennerlaufzeit 1 Stunden 0"
BLZ2S2 = 0x8839, //: "Brennerlaufzeit 2 Stunden 2"
BLZ2S1 = 0x883a, //: "Brennerlaufzeit 2 Stunden 1"
BLZ2S0 = 0x883b, //: "Brennerlaufzeit 2 Stunden 0"
AT = 0x893c, //: "Aussentemperatur" (Grad)
ATD = 0x893d, //: "gedaempfte Aussentemperatur" (Grad)
VVK = 0x893e, //: "Versionsnummer VK"
VNK = 0x893f, //: "Versionsnummer NK"
MODKENN = 0x8940, //: "Modulkennung"
NB12 = 0x8941, //: "nicht belegt"
ALARM = 0xaa42, //: "ERR_Alarmstatus"
CFG1 = 0x0000, //: "Sommar ab, HK1 Nacht-/Tag-/Urlaubstemperatur, Betriebsart"
CFG2 = 0x000E, //: "HK1 Max Temperatur, HK1 Auslegung"
CFG3 = 0x0015, //: "HK1 Aufschalttemperatur, HK1 Aussenhalt_ab"
CFG4 = 0x001c, //: "HK1 Absenkungsart, HK1 Heizsystem"
CFG5 = 0x0031, //: "HK1 Temperatur Offset, HK1 Fernbedienung, Frost ab"
CFG6 = 0x004d, //: "WW Vorgang"
CFG7 = 0x0070, //: "Gebäudeart"
CFG8 = 0x007e, //: "WW Temperatur"
CFG9 = 0x0085, //: "WW Betriebsart, WW Aufbereitung, WW Zirkulation"
CFG10 = 0x0093, //: "Sprache, Anzeige"
CFG11 = 0x009a, //: "Brennerart, Max Kesseltemperatur"
CFG12 = 0x00a1, //: "Pumplogik, Abgastemperaturschwelle"
CFG13 = 0x00a8, //: "Brenner Min Modulation, Brenner Mod Laufzeit"
};
enum SensorType {
NONE = 0,
UNSIGNED_INT,
SIGNED_INT,
UNSIGNED_INT_DIVIDED_BY_2,
STRING,
BYTE_AT_OFFSET, // a single byte, with offset in bytes specified in sensor param
BIT_AT_OFFSET, // a single bit, with offset in bits specified in sensor param
TAG_NACHT_AUTO_SELECT, // [ 0 => "Nacht", 1=> "Tag", 2=> "Automatik" ],
};
class Writer3964R;
class BuderusParamSwitch: public esphome::switch_::Switch {
public:
BuderusParamSwitch();
void setupWriting(Writer3964R * writer, Buderus_R2017_ParameterId parameterId, SensorType sensorType);
protected:
void write_state(bool state) override;
private:
Writer3964R * writer;
Buderus_R2017_ParameterId parameterId;
SensorType sensorType;
};
class BuderusParamNumber: public esphome::number::Number {
public:
BuderusParamNumber();
void setupWriting(Writer3964R * writer, Buderus_R2017_ParameterId parameterId, SensorType sensorType);
void loop();
protected:
void control(float value);
private:
Writer3964R * writer;
Buderus_R2017_ParameterId parameterId;
SensorType sensorType;
uint32_t lastWriteRequest;
bool hasPendingWriteRequest;
float pendingWriteValue;
};
struct t_Buderus_R2017_ParamDesc {
Buderus_R2017_ParameterId parameterId;
bool writable;
SensorType sensorType;
uint16_t sensorTypeParam;
const char* desc;
const char* unit;
};
typedef struct t_Buderus_R2017_ParamDesc t_Buderus_R2017_ParamDesc;
/** A BuderusValueHandler handles a value that we received from the heater. It passes the data to the configured switches, sensors and so on. */
class BuderusValueHandler {
public:
BuderusValueHandler(const t_Buderus_R2017_ParamDesc* paramDesc, esphome::sensor::Sensor * sensor);
BuderusValueHandler(const t_Buderus_R2017_ParamDesc* paramDesc, esphome::binary_sensor::BinarySensor * sensor);
BuderusValueHandler(const t_Buderus_R2017_ParamDesc* paramDesc, BuderusParamSwitch * paramSwitch);
BuderusValueHandler(const t_Buderus_R2017_ParamDesc* paramDesc, BuderusParamNumber* paramNumber);
void parseAndTransmit(uint8_t *data, size_t len);
void loop();
public:
const t_Buderus_R2017_ParamDesc * paramDesc;
private:
esphome::sensor::Sensor *sensor;
esphome::binary_sensor::BinarySensor *binarySensor;
BuderusParamSwitch *switch_;
BuderusParamNumber *number;
};
typedef std::unordered_multimap<Buderus_R2017_ParameterId, BuderusValueHandler *, std::hash<int>> ValueHandlerMap;
static ValueHandlerMap valueHandlerMap;
static const t_Buderus_R2017_ParamDesc buderusParamDesc[] = {
{CFG_WW_Temperatur, true, SensorType::BYTE_AT_OFFSET, 3, "CFG_WW_Temperatur", ""},
{CFG_WW_Aufbereitung, true, SensorType::TAG_NACHT_AUTO_SELECT, 0, "CFG_WW_Aufbereitung", ""},
// Betriebswerte 1 HK1
//{BW1HK1, false, SensorType::UNSIGNED_INT, 0, "Betriebswerte 1 HK1", ""},
{BW1HK1, false, SensorType::BIT_AT_OFFSET, 0, "HK1 Ausschaltoptimierung", ""},
{BW1HK1, false, SensorType::BIT_AT_OFFSET, 1, "HK1 Einschaltoptimierung", ""},
{BW1HK1, false, SensorType::BIT_AT_OFFSET, 2, "HK1 Automatik", ""},
{BW1HK1, false, SensorType::BIT_AT_OFFSET, 3, "HK1 Warmwasservorrang", ""},
{BW1HK1, false, SensorType::BIT_AT_OFFSET, 4, "HK1 Estrichtrocknung", ""},
{BW1HK1, false, SensorType::BIT_AT_OFFSET, 5, "HK1 Ferien", ""},
{BW1HK1, false, SensorType::BIT_AT_OFFSET, 6, "HK1 Frostschutz", ""},
{BW1HK1, false, SensorType::BIT_AT_OFFSET, 7, "HK1 Manuell", ""},
// Betriebswerte 2 HK1
//{BW2HK1, false, SensorType::UNSIGNED_INT, 0, "Betriebswerte 2 HK1", ""},
{BW2HK1, false, SensorType::BIT_AT_OFFSET, 0, "HK1 Sommer-Modus", ""},
{BW2HK1, false, SensorType::BIT_AT_OFFSET, 1, "HK1 Tag-Modus", ""},
{BW2HK1, false, SensorType::BIT_AT_OFFSET, 2, "HK1 Keine Kommunikation mit FB", ""},
{BW2HK1, false, SensorType::BIT_AT_OFFSET, 3, "HK1 FB fehlerhaft", ""},
{BW2HK1, false, SensorType::BIT_AT_OFFSET, 4, "HK1 Fehler Vorlauffuehler", ""},
{BW2HK1, false, SensorType::BIT_AT_OFFSET, 5, "HK1 Maximaler Vorlauf", ""},
{BW2HK1, false, SensorType::BIT_AT_OFFSET, 6, "HK1 Externer Stoereingang", ""},
//{BW2HK1, false, SensorType::BIT_AT_OFFSET, 7, "HK1 Frei - Party/Pause", ""}, // unklar was hier gemeint ist
{BW2HK1, false, SensorType::UNSIGNED_INT, 0, "Betriebswerte 2 HK1", ""},
{VSTHK1, false, SensorType::UNSIGNED_INT, 0, "Vorlaufsolltemperatur HK1", "°C"}, // (Grad)
{VITHK1, false, SensorType::UNSIGNED_INT, 0, "Vorlaufisttemperatur HK1", "°C"}, // (Grad)
{RSTHK1, false, SensorType::UNSIGNED_INT_DIVIDED_BY_2, 0, "Raumsolltemperatur HK1", "°C"}, // (Grad)
{RITHK1, false, SensorType::UNSIGNED_INT_DIVIDED_BY_2, 0, "Raumisttemperatur HK1", "°C"}, // (Grad)
{EOZHK1, false, SensorType::UNSIGNED_INT, 0, "Einschaltoptimierungszeit HK1", ""},
{AOZHK1, false, SensorType::UNSIGNED_INT, 0, "Ausschaltoptimierungszeit HK1", ""},
{PLHK1, false, SensorType::UNSIGNED_INT, 0, "Pumpenleistung HK1", "%"}, // (Grad)
{MSHK1, false, SensorType::SIGNED_INT, 0, "Mischerstellung HK1", "%"}, // (Grad)
{NB01, false, SensorType::NONE, 0, "nicht belegt", ""},
{NB02, false, SensorType::NONE, 0, "nicht belegt", ""},
{KLHK1_P10, false, SensorType::UNSIGNED_INT, 0, "Heizkennlinie HK1 bei + 10 Grad", "°C"}, // (Grad)
{KLHK1_P00, false, SensorType::UNSIGNED_INT, 0, "Heizkennlinie HK1 bei 0 Grad", "°C"}, // (Grad)
{KLHK1_N10, false, SensorType::UNSIGNED_INT, 0, "Heizkennlinie HK1 bei - 10 Grad", "°C"}, // (Grad)
{NB03, false, SensorType::NONE, 0, "nicht belegt", ""},
{NB04, false, SensorType::NONE, 0, "nicht belegt", ""},
{NB05, false, SensorType::NONE, 0, "nicht belegt", ""},
// Betriebswerte 1 HK2
//{BW1HK2, false, SensorType::UNSIGNED_INT, 0, "Betriebswerte 1 HK2", ""},
{BW1HK2, false, SensorType::BIT_AT_OFFSET, 0, "HK2 Ausschaltoptimierung", ""},
{BW1HK2, false, SensorType::BIT_AT_OFFSET, 1, "HK2 Einschaltoptimierung", ""},
{BW1HK2, false, SensorType::BIT_AT_OFFSET, 2, "HK2 Automatik", ""},
{BW1HK2, false, SensorType::BIT_AT_OFFSET, 3, "HK2 Warmwasservorrang", ""},
{BW1HK2, false, SensorType::BIT_AT_OFFSET, 4, "HK2 Estrichtrocknung", ""},
{BW1HK2, false, SensorType::BIT_AT_OFFSET, 5, "HK2 Ferien", ""},
{BW1HK2, false, SensorType::BIT_AT_OFFSET, 6, "HK2 Frostschutz", ""},
{BW1HK2, false, SensorType::BIT_AT_OFFSET, 7, "HK2 Manuell", ""},
// Betriebswerte 2 HK2
//{BW2HK2, false, SensorType::UNSIGNED_INT, 0, "Betriebswerte 2 HK2", ""},
{BW2HK2, false, SensorType::BIT_AT_OFFSET, 0, "HK2 Sommer-Modus", ""},
{BW2HK2, false, SensorType::BIT_AT_OFFSET, 1, "HK2 Tag-Modus", ""},
{BW2HK2, false, SensorType::BIT_AT_OFFSET, 2, "HK2 Keine Kommunikation mit FB", ""},
{BW2HK2, false, SensorType::BIT_AT_OFFSET, 3, "HK2 FB fehlerhaft", ""},
{BW2HK2, false, SensorType::BIT_AT_OFFSET, 4, "HK2 Fehler Vorlauffuehler", ""},
{BW2HK2, false, SensorType::BIT_AT_OFFSET, 5, "HK2 Maximaler Vorlauf", ""},
{BW2HK2, false, SensorType::BIT_AT_OFFSET, 6, "HK2 Externer Stoereingang", ""},
//{BW2HK2, false, SensorType::BIT_AT_OFFSET, 7, "HK2 Frei - Party/Pause", ""}, // unklar was hier gemeint ist
{VSTHK2, false, SensorType::UNSIGNED_INT, 0, "Vorlaufsolltemperatur HK2", "°C"}, // (Grad)
{VITHK2, false, SensorType::UNSIGNED_INT, 0, "Vorlaufisttemperatur HK2", "°C"}, // (Grad)
{RSTHK2, false, SensorType::UNSIGNED_INT_DIVIDED_BY_2, 0, "Raumsolltemperatur HK2", "°C"}, // (Grad)
{RITHK2, false, SensorType::UNSIGNED_INT_DIVIDED_BY_2, 0, "Raumisttemperatur HK2", "°C"}, // (Grad)
{EOZHK2, false, SensorType::UNSIGNED_INT, 0, "Einschaltoptimierungszeit HK2", ""},
{AOZHK2, false, SensorType::UNSIGNED_INT, 0, "Ausschaltoptimierungszeit HK2", ""},
{PLHK2, false, SensorType::UNSIGNED_INT, 0, "Pumpenleistung HK2", "%"},
{MSHK2, false, SensorType::SIGNED_INT, 0, "Mischerstellung HK2", "%"},
{NB06, false, SensorType::NONE, 0, "nicht belegt", ""},
{NB07, false, SensorType::NONE, 0, "nicht belegt", ""},
{KLHK2_P10, false, SensorType::UNSIGNED_INT, 0, "Heizkennlinie HK2 bei + 10 Grad", "°C"}, // (Grad)
{KLHK2_P00, false, SensorType::UNSIGNED_INT, 0, "Heizkennlinie HK2 bei 0 Grad", "°C"}, // (Grad)
{KLHK2_N10, false, SensorType::UNSIGNED_INT, 0, "Heizkennlinie HK2 bei - 10 Grad", "°C"}, // (Grad)
{NB08, false, SensorType::NONE, 0, "nicht belegt", ""},
{NB09, false, SensorType::NONE, 0, "nicht belegt", ""},
{NB10, false, SensorType::NONE, 0, "nicht belegt", ""},
// Betriebswerte 1 WW
// {BW1WW, false, SensorType::UNSIGNED_INT, 0, "Betriebswerte 1 WW", ""},
{BW1WW, false, SensorType::BIT_AT_OFFSET, 0, "WW Automatik", ""},
{BW1WW, false, SensorType::BIT_AT_OFFSET, 1, "WW Desinfektion", ""},
{BW1WW, false, SensorType::BIT_AT_OFFSET, 2, "WW Nachladung", ""},
{BW1WW, false, SensorType::BIT_AT_OFFSET, 3, "WW Ferien", ""},
{BW1WW, false, SensorType::BIT_AT_OFFSET, 4, "WW Fehler Desinfektion", ""},
{BW1WW, false, SensorType::BIT_AT_OFFSET, 5, "WW Fehler Fuehler", ""},
{BW1WW, false, SensorType::BIT_AT_OFFSET, 6, "WW Fehler WW bleibt kalt", ""},
{BW1WW, false, SensorType::BIT_AT_OFFSET, 7, "WW Fehler Anode", ""},
// Betriebswerte 2 WW
// {BW2WW, false, SensorType::UNSIGNED_INT, 0, "Betriebswerte 2 WW", ""},
{BW2WW, false, SensorType::BIT_AT_OFFSET, 0, "WW Laden", ""},
{BW2WW, false, SensorType::BIT_AT_OFFSET, 1, "WW Manuell", ""},
{BW2WW, false, SensorType::BIT_AT_OFFSET, 2, "WW Nachladen", ""}, // ist 1 bei Lade-/Nachlade-Aktivität der Warmwasser - Ladepumpe, jedoch nicht über die komplette Zeit.
{BW2WW, false, SensorType::BIT_AT_OFFSET, 3, "WW Ausschaltoptimierung", ""},
{BW2WW, false, SensorType::BIT_AT_OFFSET, 4, "WW Einschaltoptimierung", ""},
{BW2WW, false, SensorType::BIT_AT_OFFSET, 5, "WW Tag Modus", ""},
{BW2WW, false, SensorType::BIT_AT_OFFSET, 6, "WW Nachbereitung", ""}, // wird gleichzeitig mit dem 6. Bit 1, aber mit zeitlicher Verzögerung 0. Möglicherweise das Zeitfenster, in dem bei Bedarf noch Warmwasserbereitung, auch über den Tag - Heiz - Modus hinaus, stattfindet.
{BW2WW, false, SensorType::BIT_AT_OFFSET, 7, "WW Vorrangschaltung", ""}, // ist 1, solange Warmwasserbereitung mit Vorrang stattfindet.
{WWST, false, SensorType::UNSIGNED_INT, 0, "WW Solltemperatur", "°C"}, // (Grad)
{WWIT, false, SensorType::UNSIGNED_INT, 0, "WW Isttemperatur", "°C"}, // (Grad)
{OZWW, false, SensorType::UNSIGNED_INT, 0, "WW Optimierungszeit", ""},
// Pumpenansteuerung
//{LPWW, false, SensorType::UNSIGNED_INT, 0, "Ladepumpe", ""}, // ["aus", "Ladepumpe", "Warmwasserpumpe", "beide"]
{LPWW, false, SensorType::BIT_AT_OFFSET, 0, "Ladepumpe", ""},
{LPWW, false, SensorType::BIT_AT_OFFSET, 1, "Zirkulationspumpe", ""},
{LPWW, false, SensorType::BIT_AT_OFFSET, 2, "Solarpumpe Absenkung", ""},
{KVST, false, SensorType::UNSIGNED_INT, 0, "Kesselvorlaufsolltemperatur", "°C"}, // (Grad)
{KVIT, false, SensorType::UNSIGNED_INT, 0, "Kesselvorlaufisttemperatur", "°C"}, // (Grad)
{BET, false, SensorType::UNSIGNED_INT, 0, "Brennereinschalttemperatur", "°C"}, // (Grad)
{BAT, false, SensorType::UNSIGNED_INT, 0, "Brennerausschalttemperatur", "°C"}, // (Grad)
{KINT1, false, SensorType::UNSIGNED_INT, 0, "Kesselintegral 1", ""},
{KINT2, false, SensorType::UNSIGNED_INT, 0, "Kesselintegral 2", ""},
// Kesselfehler
//{KFEHL, false, SensorType::UNSIGNED_INT, 0, "Kesselfehler", ""},
{KFEHL, false, SensorType::BIT_AT_OFFSET, 0, "Fehler Brennerstoerung", ""},
{KFEHL, false, SensorType::BIT_AT_OFFSET, 1, "Fehler Kesselfuehler", ""},
{KFEHL, false, SensorType::BIT_AT_OFFSET, 2, "Fehler Zusatzfuehler", ""},
{KFEHL, false, SensorType::BIT_AT_OFFSET, 3, "Fehler Kessel bleibt kalt", ""},
{KFEHL, false, SensorType::BIT_AT_OFFSET, 4, "Fehler Abgasfuehler", ""},
{KFEHL, false, SensorType::BIT_AT_OFFSET, 5, "Fehler Abgas ueber Grenzwert", ""},
{KFEHL, false, SensorType::BIT_AT_OFFSET, 6, "Fehler Sicherungskette ausgeloest", ""},
{KFEHL, false, SensorType::BIT_AT_OFFSET, 7, "Fehler Externe Stoerung", ""},
// Kesselbetrieb
//{KBETR, false, SensorType::UNSIGNED_INT, 0, "Kesselbetrieb", ""},
{KBETR, false, SensorType::BIT_AT_OFFSET, 0, "Kessel Abgastest", ""},
{KBETR, false, SensorType::BIT_AT_OFFSET, 1, "Kessel Betrieb 1.Stufe", ""},
{KBETR, false, SensorType::BIT_AT_OFFSET, 2, "Kessel Schutz", ""},
{KBETR, false, SensorType::BIT_AT_OFFSET, 3, "Kessel unter Betrieb", ""},
{KBETR, false, SensorType::BIT_AT_OFFSET, 4, "Kessel Leistung frei", ""},
{KBETR, false, SensorType::BIT_AT_OFFSET, 5, "Kessel Leistung hoch", ""},
{KBETR, false, SensorType::BIT_AT_OFFSET, 6, "Kessel Betrieb 2.Stufe", ""},
{BANST, false, SensorType::UNSIGNED_INT, 0, "Brenneransteuerung", ""}, // 0: Brenner aus, 1 : Brenner an in Stufe 1, 2 : Brenner an in Stufe 2(laut Buderus - ungeprüft)
{ABTMP, false, SensorType::UNSIGNED_INT, 0, "Abgastemperatur", "°C"}, // (Grad)
{MODBSTELL, false, SensorType::UNSIGNED_INT, 0, "modulare Brenner Stellwert", ""},
{NB11, false, SensorType::NONE, 0, "nicht belegt", ""},
{BLZ1S2, false, SensorType::UNSIGNED_INT, 0, "Brennerlaufzeit 1 Stunden 2", "h"},
{BLZ1S1, false, SensorType::UNSIGNED_INT, 0, "Brennerlaufzeit 1 Stunden 1", "h"},
{BLZ1S0, false, SensorType::UNSIGNED_INT, 0, "Brennerlaufzeit 1 Stunden 0", "h"},
{BLZ2S2, false, SensorType::UNSIGNED_INT, 0, "Brennerlaufzeit 2 Stunden 2", "h"},
{BLZ2S1, false, SensorType::UNSIGNED_INT, 0, "Brennerlaufzeit 2 Stunden 1", "h"},
{BLZ2S0, false, SensorType::UNSIGNED_INT, 0, "Brennerlaufzeit 2 Stunden 0", "h"},
{AT, false, SensorType::SIGNED_INT, 0, "Aussentemperatur", "°C"}, // (Grad)
{ATD, false, SensorType::SIGNED_INT, 0, "Gedaempfte Aussentemperatur", "°C"}, // (Grad)
{VVK, false, SensorType::UNSIGNED_INT, 0, "Versionsnummer VK", ""},
{VNK, false, SensorType::UNSIGNED_INT, 0, "Versionsnummer NK", ""},
{MODKENN, false, SensorType::UNSIGNED_INT, 0, "Modulkennung", ""},
{NB12, false, SensorType::NONE, 0, "nicht belegt", ""},
// Alarmstatus
//{ALARM, false, SensorType::UNSIGNED_INT, 0, "Alarmstatus", ""}
{ALARM, false, SensorType::BIT_AT_OFFSET, 0, "Alarm Abgasfuehler", ""},
//{ALARM, false, SensorType::BIT_AT_OFFSET, 1, "Alarm 02", ""},
{ALARM, false, SensorType::BIT_AT_OFFSET, 2, "Alarm Kesselvorlauffuehler", ""},
//{ALARM, false, SensorType::BIT_AT_OFFSET, 3, "Alarm 08", ""},
{ALARM, false, SensorType::BIT_AT_OFFSET, 4, "Alarm Brenner", ""},
//{ALARM, false, SensorType::BIT_AT_OFFSET, 5, "Alarm 20", ""},
{ALARM, false, SensorType::BIT_AT_OFFSET, 6, "Alarm HK2-Vorlauffuehler", ""},
//{ALARM, false, SensorType::BIT_AT_OFFSET, 7, "Alarm 80", ""},
};
}
}
i also streamlined hot_water_XX and warm_water_XX to ww_XX because its more consistant and easier to read. This can also be done for heating_circuit_1 and heating_circuit_2 alias hc1 and hc2. If you rather have it like it was, feel free to change it back. If its ok, it also needs a change in the esphome yaml - so this would be a breaking change in configuration...
Will you make a pull request? I was planning to do exactly the same on the next weekend! Glad to see it already done -:)
@jensgraef @the78mole What do you two think about the streamlining suggestions?
@Bascht74 I'm always a fan of making thinks more consistent and thus simpler. I'll create a pull request on behalf of @qschneider
But on the other hand - I'm not a fan of abbreviations - they tend to make things more complicated. So I'd like warm_water to stay warm_water and not become ww. But that's not a hill I'm prepared to die on :)
I've created a pull request based on the suggested changes: #30
@the78mole @qschneider @Bascht74: Do you think we can close this issue now?
maybe we have to give the entities more "self speaking" names in the future, but for now i think it's fine.
Yes! Great!
Be able to process a single bit of a byte of a specific telegram and use that for a sensor -> read "Betriebswerte" of HK1, WW and so on.
See https://github.com/the78mole/esphome_components/issues/4#issuecomment-1336187716 for the original suggestion.