Feature: rxen/txen support for RS485 transceiver for SDM power meter (#1269)

This allows to talk to the SDM power meter through an RS485 transceiver
with separate rxen and txen pins, like on the OpenDTU Fusion board.
This commit is contained in:
Eugen 2024-09-23 21:20:03 +02:00 committed by GitHub
parent c16b3aa21b
commit 2637e32145
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 50 additions and 3 deletions

View File

@ -67,6 +67,8 @@ struct PinMapping_t {
int8_t powermeter_rx;
int8_t powermeter_tx;
int8_t powermeter_dere;
int8_t powermeter_rxen;
int8_t powermeter_txen;
};
class PinMappingClass {

View File

@ -38,6 +38,15 @@ SDM::SDM(SoftwareSerial& serial, long baud, int dere_pin, int config, int8_t rx_
this->_rx_pin = rx_pin;
this->_tx_pin = tx_pin;
}
SDM::SDM(SoftwareSerial &serial, long baud, int dere_pin, int re_pin, int config, int8_t rx_pin, int8_t tx_pin) : sdmSer(serial)
{
this->_baud = baud;
this->_dere_pin = dere_pin;
this->_re_pin = re_pin;
this->_config = config;
this->_rx_pin = rx_pin;
this->_tx_pin = tx_pin;
}
#else
SDM::SDM(SoftwareSerial& serial, long baud, int dere_pin) : sdmSer(serial) {
this->_baud = baud;
@ -73,6 +82,9 @@ void SDM::begin(void) {
if (_dere_pin != NOT_A_PIN) {
pinMode(_dere_pin, OUTPUT); //set output pin mode for DE/RE pin when used (for control MAX485)
}
if (_re_pin != NOT_A_PIN) {
pinMode(_re_pin, OUTPUT); // set output pin mode /RE pin when used (for control MAX485)
}
dereSet(LOW); //set init state to receive from SDM -> DE Disable, /RE Enable (for control MAX485)
}
@ -360,6 +372,8 @@ void SDM::flush(unsigned long _flushtime) {
void SDM::dereSet(bool _state) {
if (_dere_pin != NOT_A_PIN)
digitalWrite(_dere_pin, _state); //receive from SDM -> DE Disable, /RE Enable (for control MAX485)
if (_re_pin != NOT_A_PIN)
digitalWrite(_re_pin, _state); //receive from SDM -> /RE Enable (for control MAX485)
}
bool SDM::validChecksum(const uint8_t* data, size_t messageLength) const {

View File

@ -23,6 +23,7 @@
#if !defined ( DERE_PIN )
#define DERE_PIN NOT_A_PIN // default digital pin for control MAX485 DE/RE lines (connect DE & /RE together to this pin)
#define RE_PIN NOT_A_PIN // default digital pin for control MAX485 RE line (use DERE_PIN for DE line)
#endif
#if defined ( USE_HARDWARESERIAL )
@ -332,6 +333,7 @@ class SDM {
#else // software serial
#if defined ( ESP8266 ) || defined ( ESP32 ) // on esp8266/esp32
SDM(SoftwareSerial& serial, long baud = SDM_UART_BAUD, int dere_pin = DERE_PIN, int config = SDM_UART_CONFIG, int8_t rx_pin = SDM_RX_PIN, int8_t tx_pin = SDM_TX_PIN);
SDM(SoftwareSerial& serial, long baud = SDM_UART_BAUD, int dere_pin = DERE_PIN, int re_pin = RE_PIN, int config = SDM_UART_CONFIG, int8_t rx_pin = SDM_RX_PIN, int8_t tx_pin = SDM_TX_PIN);
#else // on avr
SDM(SoftwareSerial& serial, long baud = SDM_UART_BAUD, int dere_pin = DERE_PIN);
#endif
@ -390,6 +392,7 @@ class SDM {
#endif
long _baud = SDM_UART_BAUD;
int _dere_pin = DERE_PIN;
int _re_pin = RE_PIN;
uint16_t readingerrcode = SDM_ERR_NO_ERROR; // 4 = timeout; 3 = not enough bytes; 2 = number of bytes OK but bytes b0,b1 or b2 wrong, 1 = crc error
uint16_t msturnaround = WAITING_TURNAROUND_DELAY;
uint16_t mstimeout = RESPONSE_TIMEOUT;

View File

@ -170,6 +170,14 @@
#define POWERMETER_PIN_DERE -1
#endif
#ifndef POWERMETER_PIN_TXEN
#define POWERMETER_PIN_TXEN -1
#endif
#ifndef POWERMETER_PIN_RXEN
#define POWERMETER_PIN_RXEN -1
#endif
#ifndef W5500_SCLK
#define W5500_SCLK -1
#endif
@ -267,6 +275,8 @@ PinMappingClass::PinMappingClass()
_pinMapping.powermeter_rx = POWERMETER_PIN_RX;
_pinMapping.powermeter_tx = POWERMETER_PIN_TX;
_pinMapping.powermeter_dere = POWERMETER_PIN_DERE;
_pinMapping.powermeter_rxen = POWERMETER_PIN_RXEN;
_pinMapping.powermeter_txen = POWERMETER_PIN_TXEN;
}
PinMapping_t& PinMappingClass::get()
@ -359,6 +369,8 @@ bool PinMappingClass::init(const String& deviceMapping)
_pinMapping.powermeter_rx = doc[i]["powermeter"]["rx"] | POWERMETER_PIN_RX;
_pinMapping.powermeter_tx = doc[i]["powermeter"]["tx"] | POWERMETER_PIN_TX;
_pinMapping.powermeter_dere = doc[i]["powermeter"]["dere"] | POWERMETER_PIN_DERE;
_pinMapping.powermeter_rxen = doc[i]["powermeter"]["rxen"] | POWERMETER_PIN_RXEN;
_pinMapping.powermeter_txen = doc[i]["powermeter"]["txen"] | POWERMETER_PIN_TXEN;
return true;
}

View File

@ -28,8 +28,8 @@ bool PowerMeterSerialSdm::init()
{
const PinMapping_t& pin = PinMapping.get();
MessageOutput.printf("[PowerMeterSerialSdm] rx = %d, tx = %d, dere = %d\r\n",
pin.powermeter_rx, pin.powermeter_tx, pin.powermeter_dere);
MessageOutput.printf("[PowerMeterSerialSdm] rx = %d, tx = %d, dere = %d, rxen = %d, txen = %d \r\n",
pin.powermeter_rx, pin.powermeter_tx, pin.powermeter_dere, pin.powermeter_rxen, pin.powermeter_txen);
if (pin.powermeter_rx < 0 || pin.powermeter_tx < 0) {
MessageOutput.println("[PowerMeterSerialSdm] invalid pin config for SDM "
@ -38,8 +38,17 @@ bool PowerMeterSerialSdm::init()
}
_upSdmSerial = std::make_unique<SoftwareSerial>();
_upSdm = std::make_unique<SDM>(*_upSdmSerial, 9600, pin.powermeter_dere,
if (pin.powermeter_rxen > -1 && pin.powermeter_txen > -1){
_upSdm = std::make_unique<SDM>(*_upSdmSerial, 9600, pin.powermeter_rxen, pin.powermeter_txen,
SWSERIAL_8N1, pin.powermeter_rx, pin.powermeter_tx);
}
else
{
_upSdm = std::make_unique<SDM>(*_upSdmSerial, 9600, pin.powermeter_dere,
SWSERIAL_8N1, pin.powermeter_rx, pin.powermeter_tx);
}
_upSdm->begin();
return true;

View File

@ -116,6 +116,13 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
huaweiPinObj["cs"] = pin.huawei_cs;
huaweiPinObj["power"] = pin.huawei_power;
auto powermeterPinObj = curPin["powermeter"].to<JsonObject>();
powermeterPinObj["rx"] = pin.powermeter_rx;
powermeterPinObj["tx"] = pin.powermeter_tx;
powermeterPinObj["dere"] = pin.powermeter_dere;
powermeterPinObj["rxen"] = pin.powermeter_rxen;
powermeterPinObj["txen"] = pin.powermeter_txen;
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
}