After a long day with C++ Code, I ended up with a non-working solution. I tweaked the main code here and there, substitute the german variables with the corresponding english ones and separated the messages into their substrings.
I tried to get through the sensor data with an if statement but struggled. Here is my current progress and some description if anyone is able to point out what I missed here (@danielw? ).
#include "esphome.h"
#include <string>
//#include "sensor.h"
using namespace std;
class HausbusRead : public PollingComponent, public UARTDevice {
public:
HausbusRead(UARTComponent *parent) : PollingComponent(1000), UARTDevice(parent) {}
TextSensor *LastHausBusMessage = new TextSensor(), *LastHausBusID = new TextSensor(), *LastHausBusSensorType = new TextSensor(), *LastHausBusSensorID = new TextSensor(), *LastHausBusSensorState = new TextSensor(), *LastHausBusSensorValue = new TextSensor();
Sensor *Hausbus_taster_1395_brightness = new Sensor();
Sensor *Hausbus_taster_1395_temperature = new Sensor();
Sensor *Hausbus_taster_1395_humidity = new Sensor();
char RS485Message[36] = {};
std::string Message = "", device_id = "", sensor_type = "", sensor_id = "", sensor_state = "", sensor_value = "", outputsensor = "";
int msg_len = 0;
int point_counter = 0;
void setup() override
{
//pinMode(12, Message); // no longer necessary with RS3485 (only needed for DE/RE)
//pinMode(14, Message); // no longer necessary with RS3485 (only needed for DE/RE)
}//end of setup
void update() override
{
while (available() > 0)
{
//digitalWrite(12, LOW); // no longer necessary with RS3485 (only needed for DE/RE)
//digitalWrite(14, LOW); // no longer necessary with RS3485 (only needed for DE/RE)
byte incomingByte = read(); // get last byte from UART
switch (incomingByte) // is it the last or the first Byte?
{
case 0xFD: // every message starts with 0xFD, this means here starts a new message
msg_len = 0;
point_counter = 0;
RS485Message[msg_len] = incomingByte; // add the incoming byte to the array
break;
case 0xFE: // every message ends with 0xFE, this means the message ends here
for (int i = 1; i <=msg_len; i++) // create a string from the array for the HAss Sensor
{
Message = Message + RS485Message[i];
}//end of for
outputsensor = "Hausbus_taster_" + device_id + "_";
if (sensor_type == "BRS") { outputsensor = outputsensor + "brightness"; }
else if (sensor_type == "TMP") { outputsensor = outputsensor + "temperature"; }
else if (sensor_type == "RHD") { outputsensor = outputsensor + "humidity"; }
outputsensor->publish_state(sensor_value);
LastHausBusMessage->publish_state(Message); // push the strings to the sensors (currently for debugging purposes only)
LastHausBusID->publish_state(device_id);
LastHausBusSensorType->publish_state(sensor_type);
LastHausBusSensorID->publish_state(sensor_id);
LastHausBusSensorState->publish_state(sensor_state);
LastHausBusSensorValue->publish_state(sensor_value);
Message = ""; // Reset the strings
device_id = "";
sensor_type = "";
sensor_id = "";
sensor_state = "";
sensor_value = "";
outputsensor = "";
break;
case '.': // Count the . chars to separate the substrings of the message
point_counter++; // no break, we want to go to default after increasing the . counter
default: // in case it is not the beginning oder the end of the message
msg_len = msg_len + 1;
RS485Message[msg_len] = incomingByte; // add the last byte to the array
if (msg_len == 35)
{
msg_len = 0; // stupidest way of error handling so far
Message = "";
}//end of if
if(RS485Message[msg_len] != '.') // jump over the . chars, they are useless
{
switch (point_counter)
{
case 0: // 1st substring is the DeviceID
device_id = device_id + RS485Message[msg_len];
break;
case 1: // 2nd substring is the sensor type
sensor_type = sensor_type + RS485Message[msg_len];
break;
case 2: // 3rd substring is the sensor id
sensor_id = sensor_id + RS485Message[msg_len];
break;
case 3: // 4th substring is the sensor state
sensor_state = sensor_state + RS485Message[msg_len];
break;
case 4: // 5th substring is the sensor value
sensor_value = sensor_value + RS485Message[msg_len];
break;
}//end of switch
}//end of if
break;
}//end of switch
}//end of while
}//end of update
};//end of class
As stated before, I think I have to define all sensors of all Multitaster as TextSensors
or Sensors
in the C++ Code (currently only one device with three sensors is defined in the code above). I realized that every switch is a sensor as well, so every Multitaster has 9 sensor definitions, with 22 devices, I end up in nearly 220 variables, most work is copy-paste and with some excel magic, it is not too hard. In general the scaling is very bad, though it’s static and therefore acceptable.
But I’m a bit lost in the part where I’d like to publish the current sensor’s value
outputsensor = "Hausbus_taster_" + device_id + "_";
if (sensor_type == "BRS") { outputsensor = outputsensor + "brightness"; }
else if (sensor_type == "TMP") { outputsensor = outputsensor + "temperature"; }
else if (sensor_type == "RHD") { outputsensor = outputsensor + "humidity"; }
outputsensor->publish_state(sensor_value);
In my opinion it’s a very elegant solution, to work with variables here and to publish only what I read from UART before - for example the temperature value 19,5
of the sensor Hausbus_taster_1395_temperature
.
To accomplish that, I’d like to ‘create’ the correct sensors name (aka the correct variable name to publish) at runtime and - after that - publish exactly that one. I had no luck googling around how to convert a string value to be interpreted as the name of a variable - maybe I was looking for the wrong search terms - how is this called in a programmer’s language?
Additionally to the handling of the code above, I’m not sure how to handle the output of the code in the yaml. Currently I’m using something like
sensor:
- platform: custom
lambda: |-
auto my_hausbus = new Hausbusread(id(HausbusUART));
App.register_component(my_hausbus);
return {my_hausbus->Hausbus_taster_1395_brightness, my_hausbus->Hausbus_taster_1395_temperature, my_hausbus->Hausbus_taster_1395_humidity};
sensors:
- name: "Hausbus_taster_1395_brightness"
- name: "Hausbus_taster_1395_temperature"
- name: "Hausbus_taster_1395_humidity"
to get the values to the corresponding sensors in HA. But this scales even worse than in the variable definition. Should I really return 220 values? Usally, there is only one of the 220 values at a time, e.g. Hausbus_taster_1395_temperature = 19,5
, will the other 219 values simply be ignored in that case?
Once again: Please excuse my sometimes very stupid questions and maybe I should invest more time in googling, but it’s hard when you do not know the correct term. I hope my ignorance will help out others with the same questions one day.